using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Drawing.Drawing2D; using System.Globalization; using System.Windows.Forms; using DevComponents.DotNetBar.Charts.Style; namespace DevComponents.DotNetBar.Charts { /// /// ChartPanel is a container object which holds /// and defines ChartGraphs, which can be single or multiple. /// [TypeConverter(typeof(BlankExpandableObjectConverter))] public class ChartPanel : ChartContainer, IEffectiveStyle { #region Private variables private States _States; private ChartContainerCollection _ChartContainers; private ContainerLayout _ContainerLayout = ContainerLayout.Auto; private ChartMatrix _ChartMatrix; private List _MatrixList; private DefaultVisualStyles _DefaultVisualStyles; private ChartPanelVisualStyle _ChartPanelVisualStyle; private EffectiveStyle _EffectivePanelStyle; private List _LegendData; private LegendSource _LegendSource = (LegendSource.NestedCharts | LegendSource.NestedPanels); #endregion public ChartPanel(string name) : this() { Name = name; } public ChartPanel() { InitDefaultStates(); _EffectivePanelStyle = new EffectiveStyle(this); Legend.Visible = false; } #region InitDefaultStates private void InitDefaultStates() { SetState(States.AutoFillChartMatrix, true); SetState(States.AutoSizeChartMatrix, true); } #endregion #region Public properties #region AutoFillChartMatrix /// /// Gets or sets whether the ChartMatrix is auto filled /// from the ChartContainer collection. /// [DefaultValue(true), Category("Layout")] [Description("Indicates whether the ChartMatrix is auto filled from the ChartContainer collection.")] public bool AutoFillChartMatrix { get { return (TestState(States.AutoFillChartMatrix)); } set { if (value != AutoFillChartMatrix) { SetState(States.AutoFillChartMatrix, value); OnPropertyChangedEx("AutoFillChartMatrix", VisualChangeType.Layout); } } } #endregion #region AutoGenSeriesCollection /// /// Gets or sets whether series definitions are auto generated from the set DataSource. /// [DefaultValue(false), Category("Data")] [Description("Indicates whether series definitions are auto generated from the set DataSource.")] public bool AutoGenSeriesCollection { get { return (TestState(States.AutoGenSeriesCollection)); } set { if (value != AutoGenSeriesCollection) { SetState(States.AutoGenSeriesCollection, value); OnPropertyChangedEx("AutoGenSeriesCollection", VisualChangeType.Layout); } } } #endregion #region AutoSizeChartMatrix /// /// Gets or sets whether the ChartMatrix is auto sized /// from the ChartContainer collection. /// [DefaultValue(true), Category("Layout")] [Description("Indicates whether the ChartMatrix is auto sized from the ChartContainer collection.")] public bool AutoSizeChartMatrix { get { return (TestState(States.AutoSizeChartMatrix)); } set { if (value != AutoSizeChartMatrix) { SetState(States.AutoSizeChartMatrix, value); OnPropertyChangedEx("AutoSizeChartMatrix", VisualChangeType.Layout); } } } #endregion #region ChartContainers /// /// Gets a reference to the collection of Chart Containers (ChartPanels and Chart graphs). /// [Category("Layout")] [Description("Indicates the reference to the collection of Chart Containers (ChartPanels and Chart graphs).")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartContainerCollection ChartContainers { get { if (_ChartContainers == null) { _ChartContainers = new ChartContainerCollection(); _ChartContainers.CollectionChanged += ChartContainersCollectionChanged; } return (_ChartContainers); } internal set { if (_ChartContainers != null) _ChartContainers.CollectionChanged -= ChartContainersCollectionChanged; _ChartContainers = value; if (_ChartContainers != null) _ChartContainers.CollectionChanged += ChartContainersCollectionChanged; } } #region ChartContainersCollectionChanged void ChartContainersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { ChartControl chartControl = ChartControl; switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (ChartContainer item in e.NewItems) { item.Parent = this; if (chartControl != null) AddSelectedItems(chartControl, item); } break; case NotifyCollectionChangedAction.Replace: foreach (ChartContainer item in e.OldItems) { if (chartControl != null) RemoveSelectedItems(chartControl, item); item.Parent = null; } foreach (ChartContainer item in e.NewItems) { item.Parent = this; if (chartControl != null) AddSelectedItems(chartControl, item); } break; case NotifyCollectionChangedAction.Remove: foreach (ChartContainer item in e.OldItems) { item.Parent = null; if (chartControl != null) RemoveSelectedItems(chartControl, item); } break; } InvalidateLayout(); } #region AddSelectedItems private void AddSelectedItems(ChartControl chartControl, ChartContainer item) { BaseChart chart = item as BaseChart; if (chart != null) { if (chart.IsSelected == true) chartControl.SetSelected(item, true); } else if (item is ChartPanel) { foreach (ChartContainer citem in ((ChartPanel)item).ChartContainers) AddSelectedItems(chartControl, citem); } } #endregion #region RemoveSelectedItems private void RemoveSelectedItems(ChartControl chartControl, ChartContainer item) { BaseChart chart = item as BaseChart; if (chart != null) { if (chart.IsSelected == true) chartControl.SetSelected(item, false); } else if (item is ChartPanel) { foreach (ChartContainer citem in ((ChartPanel)item).ChartContainers) RemoveSelectedItems(chartControl, citem); } } #endregion #endregion #endregion #region ChartMatrix /// /// Gets the Matrix used to display the defined Panels and Charts in a Matrix format. /// [Category("Layout")] [Description("Indicates the Matrix used to display the defined Panels and Charts in a Matrix format.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartMatrix ChartMatrix { get { if (_ChartMatrix == null) { _ChartMatrix = new ChartMatrix(); _ChartMatrix.Parent = this; _ChartMatrix.PropertyChanged += ChartMatrix_PropertyChanged; } return (_ChartMatrix); } internal set { if (_ChartMatrix != value) { if (_ChartMatrix != null) { _ChartMatrix.PropertyChanged -= ChartMatrix_PropertyChanged; _ChartMatrix.Parent = null; } _ChartMatrix = value; if (_ChartMatrix != null) { _ChartMatrix.Parent = this; _ChartMatrix.PropertyChanged += ChartMatrix_PropertyChanged; } } } } #region ChartMatrix_PropertyChanged void ChartMatrix_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (ChartControl != null) { if (e.PropertyName.Equals("Size") || e.PropertyName.Equals("Height") || e.PropertyName.Equals("Width")) ChartControl.DoChartMatrixResizedEvent(this); if (ChartControl.InUpdateLayout == false) InvalidateLayout(); } } #endregion #endregion #region ChartPanelVisualStyle /// /// Gets or sets the visual style for the Chart Panel. /// [Category("Style")] [Description("Indicates the visual style for the Chart Panel.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartPanelVisualStyle ChartPanelVisualStyle { get { if (_ChartPanelVisualStyle == null) { _ChartPanelVisualStyle = new ChartPanelVisualStyle(); StyleVisualChangeHandler(null, _ChartPanelVisualStyle); } return (_ChartPanelVisualStyle); } set { if (_ChartPanelVisualStyle != value) { ChartPanelVisualStyle oldValue = _ChartPanelVisualStyle; _ChartPanelVisualStyle = value; OnStyleChanged("ChartPanelVisualStyle", oldValue, value); if (oldValue != null) oldValue.Dispose(); } } } #endregion #region ContainerLayout /// /// Gets or sets the layout (horizontal, vertical, matrix) for the defined Chart Containers. /// [DefaultValue(ContainerLayout.Auto), Category("Layout")] [Description("Indicates the layout (horizontal, vertical, matrix) for the defined Chart Containers.")] public ContainerLayout ContainerLayout { get { return (_ContainerLayout); } set { if (_ContainerLayout != value) { _ContainerLayout = value; OnPropertyChangedEx("ContainerLayout", VisualChangeType.Layout); } } } #endregion #region DefaultVisualStyles /// /// Gets or sets the Default Visual Styles for each Chart element. /// [Browsable(true), Category("Style"), DefaultValue(null)] [Description("Indicates the Default Visual Styles for each Chart element.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public DefaultVisualStyles DefaultVisualStyles { get { if (_DefaultVisualStyles == null) { _DefaultVisualStyles = new DefaultVisualStyles(); _DefaultVisualStyles.PropertyChanged += DefaultVisualStylesPropertyChanged; } return (_DefaultVisualStyles); } set { if (_DefaultVisualStyles != value) { if (_DefaultVisualStyles != null) _DefaultVisualStyles.PropertyChanged -= DefaultVisualStylesPropertyChanged; _DefaultVisualStyles = value; if (_DefaultVisualStyles != null) _DefaultVisualStyles.PropertyChanged += DefaultVisualStylesPropertyChanged; } } } #region DefaultVisualStylesPropertyChanged private void DefaultVisualStylesPropertyChanged(object sender, PropertyChangedEventArgs e) { VisualChangeType changeType = ((VisualPropertyChangedEventArgs)e).ChangeType; switch (changeType) { case VisualChangeType.Layout: InvalidateRender(); break; case VisualChangeType.Render: InvalidateRender(); break; } //ChartControl cc = ChartControl; //if (cc != null) // cc.UpdateStyleCount(); } #endregion #endregion #region EffectivePanelStyle /// /// Gets a reference to the panel's effective (cached, composite) style. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ChartPanelVisualStyle EffectivePanelStyle { get { return (_EffectivePanelStyle.Style); } } #endregion #region LegendSource /// /// Gets or sets the source for the items in the panel legend. /// [Category("Layout")] [Description("Indicates the source for the items in the panel legend.")] [Editor("DevComponents.Charts.Design.FlagsEnumUIEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public LegendSource LegendSource { get { return (_LegendSource); } set { if (value != _LegendSource) { _LegendSource = value; OnPropertyChangedEx("LegendSource", VisualChangeType.Layout); } } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] internal virtual bool ShouldSerializeLegendSource() { return (_LegendSource != (LegendSource.NestedCharts | LegendSource.NestedPanels)); } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] internal virtual void ResetLegendSource() { LegendSource = (LegendSource.NestedCharts | LegendSource.NestedPanels); } #endregion #endregion #region Internal properties #region LegendData internal List LegendData { get { return (_LegendData); } set { if (_LegendData != null) { foreach (ChartLegendItem item in _LegendData) item.Dispose(); } _LegendData = value; } } #endregion #endregion #region MeasureOverride protected override void MeasureOverride(ChartLayoutInfo layoutInfo) { ChartPanelVisualStyle pstyle = EffectivePanelStyle; ContainerVisualStyle cstyle = GetEffectiveContainerStyle(); if (cstyle.DropShadow.Enabled == Tbool.True) { layoutInfo.LayoutBounds.Height -= 3; layoutInfo.LayoutBounds.Width -= 3; } BoundsRelative = layoutInfo.LayoutBounds; FrameBounds = GetAdjustedBounds(BoundsRelative, cstyle.Margin); ContentBounds = GetAdjustedBounds(FrameBounds, cstyle.BorderThickness); ContentBounds = GetAdjustedBounds(ContentBounds, cstyle.Padding); layoutInfo.LayoutBounds = ContentBounds; base.MeasureOverride(layoutInfo); ContentBounds = layoutInfo.LayoutBounds; ContentBoundsEx = ContentBounds; if (AutoFillChartMatrix == true) AutoFillMatrix(layoutInfo); else FillMatrix(); Size size = MeasureMatrix(layoutInfo, pstyle); Size minContentSize = Dpi.Size(MinContentSize); if (size.Width < minContentSize.Width) size.Width = minContentSize.Width; if (size.Height < minContentSize.Height) size.Height = minContentSize.Height; Rectangle r = ContentBoundsEx; if (size.Width > r.Width) r.Width = size.Width; if (size.Height > r.Height) r.Height = size.Height; ContentBoundsEx = r; if ((ContentBoundsEx.Width > ContentBounds.Width && ContentBoundsEx.Height == ContentBounds.Height) || (ContentBoundsEx.Height > ContentBounds.Height && ContentBoundsEx.Width == ContentBounds.Width)) { layoutInfo.LayoutBounds = ContentBounds; if (ContentBoundsEx.Width > ContentBounds.Width) layoutInfo.LayoutBounds.Height -= (HScrollBar.Height + 1); if (ContentBoundsEx.Height > ContentBounds.Height) layoutInfo.LayoutBounds.Width -= (VScrollBar.Width + 1); size = MeasureMatrix(layoutInfo, pstyle); if (size.IsEmpty == false) { if (size.Width < minContentSize.Width) size.Width = minContentSize.Width; if (size.Height < minContentSize.Height) size.Height = minContentSize.Height; r = ContentBoundsEx; r.Size = size; ContentBoundsEx = r; } } else if (ContentBoundsEx.Width > ContentBounds.Width && ContentBoundsEx.Height > ContentBounds.Height) { r.Width += (VScrollBar.Width + 1); r.Height += (HScrollBar.Height + 1); ContentBoundsEx = r; } } #region FillMatrix private void FillMatrix() { Size size = Size.Empty; _MatrixList = new List(); foreach (ChartContainer cc in ChartContainers) { if (cc.Visible == true) { if (cc.MatrixDisplayBounds.Right > 0 && cc.MatrixDisplayBounds.Bottom > 0) { _MatrixList.Add(cc); if (cc.MatrixDisplayBounds.Right > size.Width) size.Width = cc.MatrixDisplayBounds.Right; if (cc.MatrixDisplayBounds.Bottom > size.Height) size.Height = cc.MatrixDisplayBounds.Bottom; } } } if (AutoSizeChartMatrix == true) { ChartMatrix.Size = size; } else { if (size.Width > ChartMatrix.Size.Width || size.Height > ChartMatrix.Size.Height) throw new Exception("ChartMatrix not large enough for assigned containers."); } ChartMatrix.Clear(); _MatrixList.Sort(new MatrixComparer()); foreach (ChartContainer cc in _MatrixList) { Rectangle r = cc.MatrixDisplayBounds; for (int i = r.X; i < r.Right; i++) { for (int j = r.Y; j < r.Bottom; j++) ChartMatrix[i, j] = cc; } } } #endregion #region AutoFillMatrix private void AutoFillMatrix(ChartLayoutInfo layoutInfo) { _MatrixList = new List(); int count = VisibleContainerCount(); if (count > 0) { Size size = ChartMatrix.Size; ContainerLayout clayout = ContainerLayout; if (AutoSizeChartMatrix == true) size = GetAutoMatrixSize(layoutInfo, count, ref clayout); ChartMatrix.Size = size; int n = -1; if (clayout == ContainerLayout.Horizontal) { for (int i = 0; i < size.Height; i++) { for (int j = 0; j < size.Width; j++) { ChartContainer container = GetNextVisibleContainer(ref n); if (container == null) { i = size.Height; break; } ChartMatrix[j, i] = container; container.MatrixDisplayBounds = new Rectangle(j, i, 1, 1); _MatrixList.Add(container); } } } else { for (int i = 0; i < size.Width; i++) { for (int j = 0; j < size.Height; j++) { ChartContainer container = GetNextVisibleContainer(ref n); if (container == null) { i = size.Width; break; } ChartMatrix[i, j] = container; container.MatrixDisplayBounds = new Rectangle(i, j, 1, 1); _MatrixList.Add(container); } } } } } #region VisibleContainerCount private int VisibleContainerCount() { int count = 0; foreach (ChartContainer cc in ChartContainers) { if (cc.Visible == true) count++; } return (count); } #endregion #region GetAutoMatrixSize private Size GetAutoMatrixSize( ChartLayoutInfo layoutInfo, int count, ref ContainerLayout clayout) { if (count > 0) { if (ContainerLayout == ContainerLayout.Horizontal) return (new Size(count, 1)); if (ContainerLayout == ContainerLayout.Vertical) return (new Size(1, count)); double w = Math.Ceiling(Math.Sqrt((double)count)); double h = (w * w == count) ? w : Math.Ceiling(count / w); if (w != h) { if ((layoutInfo.LayoutBounds.Width > layoutInfo.LayoutBounds.Height && w < h) || (layoutInfo.LayoutBounds.Width < layoutInfo.LayoutBounds.Height && w > h)) { clayout = ContainerLayout.Vertical; return (new Size((int)h, (int)w)); } } clayout = ContainerLayout.Horizontal; return (new Size((int)w, (int)h)); } return (Size.Empty); } #endregion #region GetNextVisibleContainer private ChartContainer GetNextVisibleContainer(ref int n) { n++; while (n < ChartContainers.Count) { if (ChartContainers[n].Visible == true) return (ChartContainers[n]); n++; } return (null); } #endregion #endregion #region MeasureMatrix private Size MeasureMatrix(ChartLayoutInfo layoutInfo, ChartPanelVisualStyle style) { int hLen = GetMatrixLayout(layoutInfo, ContainerLayout.Horizontal); int vLen = GetMatrixLayout(layoutInfo, ContainerLayout.Vertical); Rectangle layoutBounds = layoutInfo.LayoutBounds; Point ptLayout = layoutBounds.Location; for (int i = 0; i < ChartMatrix.Width; i++) { int width = ChartMatrix.ColumnProperties[i].Length; Point ptBounds = ptLayout; for (int j = 0; j < ChartMatrix.Height; j++) { int height = ChartMatrix.RowProperties[j].Length; ChartMatrix.BoundsArray[i, j] = new Rectangle(ptBounds, new Size(width, height)); ptBounds.Y += height; } ptLayout.X += width; } int dx = style.DividerLineX.LineWidth / 2; int dy = style.DividerLineY.LineWidth / 2; foreach (ChartContainer cc in _MatrixList) { Rectangle r = GetMatrixBounds(cc, dx, dy); cc.BoundsRelative = r; layoutInfo.LayoutBounds = cc.BoundsRelative; cc.Measure(layoutInfo); } AlignMatrix(layoutInfo); return (new Size(hLen, vLen)); } #region GetMatrixBounds private Rectangle GetMatrixBounds(ChartContainer cc, int dx, int dy) { Rectangle r = Rectangle.Empty; Rectangle ccb = cc.MatrixDisplayBounds; for (int i = ccb.X; i < ccb.Right; i++) { for (int j = ccb.Y; j < ccb.Bottom; j++) { if (r.IsEmpty == true) r = ChartMatrix.BoundsArray[i, j]; else r = Rectangle.Union(r, ChartMatrix.BoundsArray[i, j]); } } if (ccb.X != 0) { r.X += dy; r.Width -= dy; } if (ccb.Right != ChartMatrix.Width) r.Width -= dy; if (ccb.Y != 0) { r.Y += dx; r.Height -= dx; } if (ccb.Bottom != ChartMatrix.Height) r.Height -= dx; return (r); } #endregion #region AlignMatrix private void AlignMatrix(ChartLayoutInfo layoutInfo) { for (int i = 0; i < ChartMatrix.Width; i++) { Vector v = GetMatrixColumnVector(i); UpdateMatrixColumnBounds(v, i); } for (int i = 0; i < ChartMatrix.Height; i++) { Vector v = GetMatrixRowVector(i); UpdateMatrixRowBounds(v, i); } foreach (ChartContainer cc in _MatrixList) { if (cc.MatrixColumnAligned == true || cc.MatrixRowAligned == true) { cc.MatrixColumnAligned = false; cc.MatrixRowAligned = false; layoutInfo.LayoutBounds = cc.BoundsRelative; cc.Measure(layoutInfo); } } } #region GetMatrixColumnVector private Vector GetMatrixColumnVector(int index) { Vector v = new Vector(); foreach (ChartContainer cc in _MatrixList) { Rectangle cb = cc.ContentBounds; if (cc.MatrixDisplayBounds.X == index) { if (cc.MatrixAlignStartColumn == true) { if (v.IsEmpty == true) { v.Start = cb.X; v.End = cb.Right; } else { if (cb.X > v.Start) { int n = cb.X - v.Start; v.Start += n; v.End -= n; } } } } if (cc.MatrixDisplayBounds.Right - 1 == index) { if (cc.MatrixAlignEndColumn == true) { if (v.IsEmpty == true) { v.End = cb.Right; } else { if (cb.Right < v.End) { int n = v.End - cb.Right; v.End -= n; } } } } } return (v); } #endregion #region UpdateMatrixColumnBounds private void UpdateMatrixColumnBounds(Vector v, int index) { foreach (ChartContainer cc in _MatrixList) { Rectangle cb = cc.ContentBounds; Rectangle t = cc.BoundsRelative; if (cc.MatrixDisplayBounds.X == index) { if (cc.MatrixAlignStartColumn == true) { if (cb.X != v.Start) { t.X += (v.Start - cb.X); t.Width -= (v.Start - cb.X); cc.MatrixColumnAligned = true; } } } if (cc.MatrixDisplayBounds.Right - 1 == index) { if (cc.MatrixAlignEndColumn == true) { if (cb.Right != v.End) { t.Width -= (cb.Right - v.End); cc.MatrixColumnAligned = true; } } } cc.BoundsRelative = t; } } #endregion #region GetMatrixRowVector private Vector GetMatrixRowVector(int index) { Vector v = new Vector(); foreach (ChartContainer cc in _MatrixList) { Rectangle cb = cc.ContentBounds; if (cc.MatrixDisplayBounds.Y == index) { if (cc.MatrixAlignStartRow == true) { if (v.IsEmpty == true) { v.Start = cb.Y; v.End = cb.Bottom; } else { if (cb.Y > v.Start) { int n = (cb.Y - v.Start); v.Start += n; v.End -= n; } } } } if (cc.MatrixDisplayBounds.Bottom - 1 == index) { if (cc.MatrixAlignEndRow == true) { if (v.IsEmpty == true) { v.Start = cb.Y; v.End = cb.Bottom; } else { if (cb.Bottom < v.End) v.End = cb.Bottom; } } } } return (v); } #endregion #region UpdateMatrixRowBounds private void UpdateMatrixRowBounds(Vector v, int index) { foreach (ChartContainer cc in _MatrixList) { if (cc.MatrixDisplayBounds.Y == index) { Rectangle cb = cc.ContentBounds; Rectangle t = cc.BoundsRelative; if (cc.MatrixAlignStartRow == true) { if (cb.Y != v.Start) { t.Y += (v.Start - cb.Y); t.Height -= (v.Start - cb.Y); cc.MatrixRowAligned = true; } } if (cc.MatrixAlignEndRow == true) { if (cb.Bottom != v.End) { t.Height -= (cb.Bottom - v.End); cc.MatrixRowAligned = true; } } cc.BoundsRelative = t; } } } #endregion #endregion #region RowComparer private class MatrixComparer : IComparer { public int Compare(ChartContainer x, ChartContainer y) { return (x.MatrixDisplayOrder - y.MatrixDisplayOrder); } } #endregion #region GetMatrixLayout private int GetMatrixLayout( ChartLayoutInfo layoutInfo, ContainerLayout containerLayout) { int fillBase; int noFillBase; CalculateMatrixFillData(layoutInfo, containerLayout, out fillBase, out noFillBase); int length = CalcMatrixContentSize(layoutInfo, containerLayout, fillBase, noFillBase); return (length); } #region CalculateMatrixFillData private void CalculateMatrixFillData(ChartLayoutInfo layoutInfo, ContainerLayout containerLayout, out int fillBase, out int noFillBase) { fillBase = 0; noFillBase = 0; if (containerLayout == ContainerLayout.Horizontal) { for (int i = 0; i < ChartMatrix.Width; i++) { MatrixRowColProperties props = ChartMatrix.ColumnProperties[i]; if (props.AutoSizeMode == AutoSizeMode.NotSet) { if (ChartMatrix[i] != null && AutoSizeMode != AutoSizeMode.None) fillBase += ChartMatrix[i].FillWeight; else noFillBase += props.Length; } else { if (props.AutoSizeMode != AutoSizeMode.None) fillBase += props.FillWeight; else noFillBase += props.Length; } } } else { for (int i = 0; i < ChartMatrix.Height; i++) { MatrixRowColProperties props = ChartMatrix.RowProperties[i]; if (props.AutoSizeMode == AutoSizeMode.NotSet) { if (ChartMatrix[i] != null && AutoSizeMode != AutoSizeMode.None) fillBase += ChartMatrix[i].FillWeight; else noFillBase += props.Length; } else { if (props.AutoSizeMode != AutoSizeMode.None) fillBase += props.FillWeight; else noFillBase += props.Length; } } } } #endregion #region CalcMatrixContentSize private int CalcMatrixContentSize(ChartLayoutInfo layoutInfo, ContainerLayout containerLayout, int fillBase, int noFillBase) { int length; if (containerLayout == ContainerLayout.Horizontal) length = CalcHorizontalMatrixContentSize(layoutInfo, fillBase, noFillBase); else length = CalctVerticalMatrixContentSize(layoutInfo, fillBase, noFillBase); return (length); } #region CalcHorizontalMatrixContentSize private int CalcHorizontalMatrixContentSize( ChartLayoutInfo layoutInfo, int fillBase, int noFillBase) { int lenNeeded = 0; int n = layoutInfo.LayoutBounds.Width - noFillBase; for (int i = 0; i < ChartMatrix.Width; i++) { MatrixRowColProperties props = ChartMatrix.ColumnProperties[i]; int length = 0; AutoSizeMode autoSizeMode = props.AutoSizeMode; if (autoSizeMode == AutoSizeMode.NotSet) autoSizeMode = AutoSizeMode; if (fillBase > 0) { int fillWeight = (ChartMatrix[i] != null && props.AutoSizeMode == AutoSizeMode.NotSet) ? ChartMatrix[i].FillWeight : props.FillWeight; if (fillWeight != 0) { if (i == ChartMatrix.Width - 1) length = layoutInfo.LayoutBounds.Width - lenNeeded; else length = (int)(n * (float)fillWeight / fillBase); } } int minLength = (props.MinimumLength > 0) ? props.MinimumLength : ChartMatrix.DefaultCellSize.Width; length = Math.Max(length, minLength); props.Length = length; lenNeeded += length; } return (lenNeeded); } #endregion #region CalctVerticalMatrixContentSize private int CalctVerticalMatrixContentSize( ChartLayoutInfo layoutInfo, int fillBase, int noFillBase) { int lengthNeeded = 0; int n = layoutInfo.LayoutBounds.Height - noFillBase; for (int i = 0; i < ChartMatrix.Height; i++) { MatrixRowColProperties props = ChartMatrix.RowProperties[i]; int length = 0; AutoSizeMode autoSizeMode = props.AutoSizeMode; if (autoSizeMode == AutoSizeMode.NotSet) autoSizeMode = AutoSizeMode; if (fillBase > 0 && autoSizeMode != AutoSizeMode.None) { if (props.FillWeight != 0) { if (i == ChartMatrix.Height - 1) length = layoutInfo.LayoutBounds.Height - lengthNeeded; else length = (int)(n * (float)props.FillWeight / fillBase); } } int minLength = (props.MinimumLength > 0) ? props.MinimumLength : ChartMatrix.DefaultCellSize.Height; length = Math.Max(length, minLength); props.Length = length; lengthNeeded += length; } return (lengthNeeded); } #endregion #endregion #endregion #endregion #endregion #region ArrangeOverride protected override void ArrangeOverride(ChartLayoutInfo layoutInfo) { base.ArrangeOverride(layoutInfo); layoutInfo.ScrollOffset.X += HScrollOffset; layoutInfo.ScrollOffset.Y += VScrollOffset; Rectangle scContentBounds = GetScrollBounds(ContentBounds); _ChartMatrix.ScrollOffset = layoutInfo.ScrollOffset; foreach (ChartContainer cc in _MatrixList) { if (cc.Visible == true) { cc.Arrange(layoutInfo); cc.Displayed = cc.Bounds.IntersectsWith(scContentBounds); } } layoutInfo.ScrollOffset.X -= HScrollOffset; layoutInfo.ScrollOffset.Y -= VScrollOffset; } #endregion #region RenderOverride protected override void RenderOverride(ChartRenderInfo renderInfo) { Graphics g = renderInfo.Graphics; ChartPanelVisualStyle pstyle = EffectivePanelStyle; ContainerVisualStyle cstyle = GetEffectiveContainerStyle(); Rectangle scFrameBounds = GetScrollBounds(FrameBounds); Rectangle scContentBounds = GetScrollBounds(ContentBounds); Rectangle scDisplayBounds = GetDisplayBounds(scContentBounds); RenderPanelBackground(g, scFrameBounds, cstyle); cstyle.RenderBorder(g, scFrameBounds); Rectangle imageBounds = GetImageBounds(FrameBounds, cstyle); if (cstyle.ImageOverlay != ImageOverlay.Top) cstyle.RenderBackgroundFigure(g, imageBounds); Region clip = g.Clip; g.SetClip(scContentBounds, CombineMode.Intersect); if (ChartMatrix.Size.Width > 0 && ChartMatrix.Size.Height > 0) RenderMatrix(renderInfo, pstyle); if (_MatrixList == null || _MatrixList.Count <= 0) RenderEmptyText(g, cstyle, scDisplayBounds); if (cstyle.ImageOverlay == ImageOverlay.Top) cstyle.RenderBackgroundFigure(g, imageBounds); RenderScrollbars(renderInfo); g.Clip = clip; if (cstyle.DropShadow.Enabled == Tbool.True) cstyle.DropShadow.RenderDropShadow(g, scFrameBounds, true, true); base.RenderOverride(renderInfo); } #region RenderPanelBackground private void RenderPanelBackground( Graphics g, Rectangle bounds, ContainerVisualStyle cstyle) { ChartControl chartControl = ChartControl; if (chartControl.DoPreRenderPanelBackgroundEvent(g, this, bounds) == false) { cstyle.RenderBackground(g, bounds); chartControl.DoPostRenderPanelBackgroundEvent(g, this, bounds); } } #endregion #region GetImageBounds private Rectangle GetImageBounds(Rectangle bounds, ContainerVisualStyle style) { bounds = GetAdjustedBounds(bounds, style.BorderThickness); Rectangle scBounds = GetScrollBounds(bounds); if (HScrollBar.Visible == true) scBounds.Height -= HScrollBar.Height; if (VScrollBar.Visible == true) scBounds.Width -= VScrollBar.Width; return (scBounds); } #endregion #region RenderMatrix private void RenderMatrix(ChartRenderInfo renderInfo, ChartPanelVisualStyle style) { Graphics g = renderInfo.Graphics; // Render divider lines switch (ChartMatrix.DividerLines) { case DividerLines.Horizontal: RenderDividerLinesX(g, style.DividerLineX); break; case DividerLines.Vertical: RenderDividerLinesY(g, style.DividerLineY); break; case DividerLines.BothXy: RenderDividerLinesX(g, style.DividerLineX); RenderDividerLinesY(g, style.DividerLineY); break; case DividerLines.BothYx: RenderDividerLinesY(g, style.DividerLineY); RenderDividerLinesX(g, style.DividerLineX); break; } // Render each matrix item if (_MatrixList != null && _MatrixList.Count > 0) { foreach (ChartContainer cc in _MatrixList) cc.Render(renderInfo); } } #region RenderDividerLinesX private void RenderDividerLinesX(Graphics g, DividerLineVisualStyle style) { if (style.LinePattern != LinePattern.None && style.LineWidth != 0) { LinePattern pattern = (style.LinePattern == LinePattern.NotSet) ? LinePattern.Solid : style.LinePattern; int thickness = (style.LineWidth > 0) ? style.LineWidth : 1; int n = ChartMatrix.Width - 1; int xoffset = _ChartMatrix.ScrollOffset.X; int yoffset = _ChartMatrix.ScrollOffset.Y; for (int i = 1; i < ChartMatrix.Height; i++) { Point pt1 = ChartMatrix.BoundsArray[0, i].Location; Point pt2 = ChartMatrix.BoundsArray[n, i].Location; pt1.X -= xoffset; pt1.Y -= yoffset; pt2.X -= xoffset; pt2.Y -= yoffset; pt2.X += ChartMatrix.BoundsArray[n, i].Width; using (Pen pen = new Pen(style.LineColor, Dpi.Width(style.LineWidth))) { pen.DashStyle = (DashStyle)pattern; g.DrawLine(pen, pt1, pt2); } } } } #endregion #region RenderDividerLinesY private void RenderDividerLinesY(Graphics g, DividerLineVisualStyle style) { if (style.LinePattern != LinePattern.None && style.LineWidth != 0) { LinePattern pattern = (style.LinePattern == LinePattern.NotSet) ? LinePattern.Solid : style.LinePattern; int thickness = (style.LineWidth > 0) ? style.LineWidth : 1; int n = ChartMatrix.Height - 1; int xoffset = _ChartMatrix.ScrollOffset.X; int yoffset = _ChartMatrix.ScrollOffset.Y; for (int i = 1; i < ChartMatrix.Width; i++) { Point pt1 = ChartMatrix.BoundsArray[i, 0].Location; Point pt2 = ChartMatrix.BoundsArray[i, n].Location; pt1.X -= xoffset; pt1.Y -= yoffset; pt2.X -= xoffset; pt2.Y -= yoffset; pt2.Y += ChartMatrix.BoundsArray[i, n].Height; using (Pen pen = new Pen(style.LineColor, Dpi.Height(thickness))) { pen.DashStyle = (DashStyle)pattern; g.DrawLine(pen, pt1, pt2); } } } } #endregion #endregion #endregion #region Mouse handling #region OnMouseMove protected override bool OnMouseMove(MouseEventArgs e) { if (base.OnMouseMove(e) == true) return (true); return (false); } #endregion #endregion #region OnResize protected override bool OnResize(EventArgs e) { InvalidateLayout(); foreach (ChartContainer cc in ChartContainers) cc.InternalOnResize(e); return (base.OnResize(e)); } #endregion #region GetElementAt /// /// Gets the visua element at the given Point. /// /// /// public override ChartVisualElement GetElementAt(Point pt) { ChartVisualElement item = base.GetElementAt(pt); if (item == null) { if (ContentBounds.Contains(pt)) { if (ChartMatrix.IsEmpty == false) { item = ChartMatrix.GetElementAt(pt); if (item != null && item.Visible == true) { if (item.Bounds.Contains(pt)) { ChartVisualElement subItem = item.GetElementAt(pt); if (subItem != null) return (subItem); return (item); } return (null); } } } } return (item); } #endregion #region GetMatrixCoordAt /// /// Gets the matric coordinate (row/column) at the given Point. /// /// /// /// /// true if valid coordinate is returned public bool GetMatrixCoordAt(Point pt, ref int column, ref int row) { if (ContentBounds.Contains(pt)) return (ChartMatrix.GetMatrixCoordAt(pt, ref column, ref row)); return (false); } #endregion #region GetMatrixCoordOf /// /// Gets the matric coordinate (row/column) of the given container. /// /// /// /// /// true if valid coordinate returned. public bool GetMatrixCoordOf(ChartContainer item, ref int row, ref int column) { return (ChartMatrix.GetMatrixCoordOf(item, ref row, ref column)); } #endregion #region Style handling #region ApplyStyles public override void ApplyStyles(BaseVisualStyle style) { ChartPanelVisualStyle pstyle = style as ChartPanelVisualStyle; if (pstyle != null) { ApplyParentStyles(pstyle, Parent as ChartContainer); pstyle.DividerLineX.ApplyStyle(DefaultVisualStyles.DividerLineVisualStyle); pstyle.DividerLineY.ApplyStyle(DefaultVisualStyles.DividerLineVisualStyle); pstyle.ApplyStyle(DefaultVisualStyles.ChartPanelVisualStyle); pstyle.ApplyStyle(ChartPanelVisualStyle); } } #region ApplyParentStyles private void ApplyParentStyles(ChartPanelVisualStyle pstyle, ChartContainer item) { if (item != null) { ApplyParentStyles(pstyle, item.Parent as ChartContainer); ChartPanel panel = item as ChartPanel; if (panel != null) { pstyle.DividerLineX.ApplyStyle(panel.DefaultVisualStyles.DividerLineVisualStyle); pstyle.DividerLineY.ApplyStyle(panel.DefaultVisualStyles.DividerLineVisualStyle); pstyle.ApplyStyle(panel.DefaultVisualStyles.ChartPanelVisualStyle); } } else { pstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartPanelVisualStyle); pstyle.DividerLineX.ApplyStyle(ChartControl.DefaultVisualStyles.DividerLineVisualStyle); pstyle.DividerLineY.ApplyStyle(ChartControl.DefaultVisualStyles.DividerLineVisualStyle); pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartPanelVisualStyle); } } #endregion #endregion #region ClearEffectiveStyles protected override void ClearEffectiveStyles() { base.ClearEffectiveStyles(); _EffectivePanelStyle.InvalidateStyle(); } #endregion #endregion #region ILegendData #region GetLegendData public override List GetLegendData() { LegendData = new List(); if (LegendSource != LegendSource.None) { ChartContainerCollection containers = ChartContainers; foreach (ChartContainer cc in containers) { if ((cc is ChartPanel) && ((LegendSource & LegendSource.NestedPanels) != 0) || (cc is BaseChart) && ((LegendSource & LegendSource.NestedCharts) != 0)) { List data = cc.GetLegendData(); if (data != null && data.Count > 0) AddLegendItems(data); } } } return (_LegendData); } #region AddLegendItems private void AddLegendItems(List items) { foreach (ChartLegendItem item in items) { ChartLegendItem likeItem = null; if (Legend.CombineLikeItems == true) likeItem = FindLikeItems(item); if (likeItem == null) { likeItem = new ChartLegendItem(); likeItem.Parent = Legend; likeItem.Name = item.Name; likeItem.ItemText = item.ItemText; _LegendData.Add(likeItem); } likeItem.ChartItems.AddRange(item.ChartItems); } } #region FindLikeItems private ChartLegendItem FindLikeItems(ChartLegendItem item) { string itemName = item.Name ?? item.ItemText; if (String.IsNullOrEmpty(itemName) == false) { foreach (ChartLegendItem likeItem in _LegendData) { string likeName = likeItem.Name ?? likeItem.ItemText; if (String.IsNullOrEmpty(likeName) == false) { if (likeName.Equals(itemName) == true) return (likeItem); } } } return (null); } #endregion #endregion #endregion #endregion #region GetContainerByName /// /// Gets the ChartContainer object from the given name. /// /// /// public ChartContainer GetContainerByName(string name) { return (GetContainerByName(name, false)); } /// /// Gets the ChartContainer object from the given name, with /// optional searching of nested panels/charts. /// /// /// /// public ChartContainer GetContainerByName(string name, bool searchNested) { if (String.IsNullOrEmpty(name) == true) return (null); if (_ChartContainers != null) { foreach (ChartContainer container in _ChartContainers) { if (name.Equals(container.Name) == true) return (container); else if (searchNested == true) { ChartPanel panel = container as ChartPanel; if (panel != null) { ChartContainer item = panel.GetContainerByName(name, true); if (item != null) return (item); } } } } return (null); } #endregion #region GetChartByName /// /// Gets the BaseChart from the given name. /// /// /// public BaseChart GetChartByName(string name) { return (GetChartByName(name, false)); } /// /// Gets the BaseChart from the given name, optionally searching /// nested panels and charts. /// /// /// /// public BaseChart GetChartByName(string name, bool searchNested) { if (String.IsNullOrEmpty(name) == true) return (null); if (_ChartContainers != null) { foreach (ChartContainer container in _ChartContainers) { if (container is BaseChart) { if (name.Equals(container.Name) == true) return ((BaseChart)container); } else if (searchNested == true) { ChartPanel panel = container as ChartPanel; if (panel != null) { BaseChart item = panel.GetChartByName(name, true); if (item != null) return (item); } } } } return (null); } #endregion #region GetPanelByName /// /// Gets the ChartPanel from the given name. /// /// /// public ChartPanel GetPanelByName(string name) { return (GetPanelByName(name, false)); } /// /// Gets the ChartPanel from the given name, optionally /// searching through nested panels. /// /// /// /// public ChartPanel GetPanelByName(string name, bool searchNested) { if (String.IsNullOrEmpty(name) == true) return (null); if (_ChartContainers != null) { foreach (ChartContainer container in _ChartContainers) { ChartPanel panel = container as ChartPanel; if (panel != null) { if (name.Equals(panel.Name) == true) return (panel); if (searchNested == true) { ChartPanel item = panel.GetPanelByName(name, true); if (item != null) return (item); } } } } return (null); } #endregion #region Copy/CopyTo public override ChartVisualElement Copy() { ChartPanel copy = new ChartPanel(); CopyTo(copy); return (copy); } public override void CopyTo(ChartVisualElement copy) { ChartPanel c = copy as ChartPanel; if (c != null) { base.CopyTo(c); c.AutoFillChartMatrix = AutoFillChartMatrix; c.AutoGenSeriesCollection = AutoGenSeriesCollection; c.AutoSizeChartMatrix = AutoSizeChartMatrix; foreach (ChartContainer cc in ChartContainers) c.ChartContainers.Add((ChartContainer)cc.Copy()); c.ChartMatrix = ChartMatrix.Copy(); c.ChartPanelVisualStyle = (_ChartPanelVisualStyle != null) ? ChartPanelVisualStyle.Copy() : null; c.ContainerLayout = ContainerLayout; c.DefaultVisualStyles = (_DefaultVisualStyles != null) ? DefaultVisualStyles.Copy() : null; c.LegendSource = LegendSource; } } #endregion #region GetSerialData internal override SerialElementCollection GetSerialData(string serialName) { SerialElementCollection sec = new SerialElementCollection(); if (serialName != null) { if (serialName.Equals("") == true) serialName = "ChartPanel"; sec.AddStartElement(serialName); } sec.AddValue("AutoFillChartMatrix", AutoFillChartMatrix, true); sec.AddValue("AutoGenSeriesCollection", AutoGenSeriesCollection, false); sec.AddValue("AutoSizeChartMatrix", AutoSizeChartMatrix, true); if (ChartContainers.Count > 0) { sec.AddStartElement("ChartContainers count=\"" + ChartContainers.Count + "\""); foreach (ChartContainer cc in ChartContainers) sec.AddElement(cc.GetSerialData("")); sec.AddEndElement("ChartContainers"); } if (_ChartMatrix != null && _ChartMatrix.IsEmpty == false) { if (AutoFillChartMatrix == false) sec.AddElement(_ChartMatrix.GetSerialData()); } if (_ChartPanelVisualStyle != null && _ChartPanelVisualStyle.IsEmpty == false) sec.AddElement(_ChartPanelVisualStyle.GetSerialData("ChartPanelVisualStyle")); sec.AddValue("ContainerLayout", ContainerLayout, ContainerLayout.Auto); if (_DefaultVisualStyles != null && _DefaultVisualStyles.IsEmpty == false) sec.AddElement(_DefaultVisualStyles.GetSerialData()); sec.AddValue("LegendSource", LegendSource, (LegendSource.NestedCharts | LegendSource.NestedPanels)); sec.AddElement(base.GetSerialData(null)); if (serialName != null) sec.AddEndElement(serialName); return (sec); } #endregion #region PutSerialData #region ProcessValue internal override void ProcessValue(SerialElement se) { switch (se.Name) { case "AutoFillChartMatrix": AutoFillChartMatrix = bool.Parse(se.StringValue); break; case "AutoGenSeriesCollection": AutoGenSeriesCollection = bool.Parse(se.StringValue); break; case "AutoSizeChartMatrix": AutoSizeChartMatrix = bool.Parse(se.StringValue); break; case "ContainerLayout": ContainerLayout = (ContainerLayout)se.GetValueEnum(typeof(ContainerLayout)); break; case "LegendSource": LegendSource = (LegendSource)se.GetValueEnum(typeof(LegendSource)); break; default: base.ProcessValue(se); break; } } #endregion #region ProcessCollection internal override void ProcessCollection(SerialElement se) { SerialElementCollection sec = se.Sec; switch (se.Name) { case "ChartPanel": case "ChartContainers": sec.PutSerialData(this); break; case "ChartXy": string name = sec.GetItemValue("Name"); ChartXy chartXy = new ChartXy(name); sec.PutSerialData(chartXy); ChartContainers.Add(chartXy); break; case "ChartMatrix": sec.PutSerialData(ChartMatrix); break; case "ChartPanelVisualStyle": sec.PutSerialData(ChartPanelVisualStyle); break; case "DefaultVisualStyles": sec.PutSerialData(DefaultVisualStyles); break; case "PieChart": string pname = sec.GetItemValue("Name"); PieChart pieChart = new PieChart(pname); sec.PutSerialData(pieChart); ChartContainers.Add(pieChart); break; default: base.ProcessCollection(se); break; } } #endregion #endregion #region States [Flags] private enum States : uint { AutoFillChartMatrix = (1U << 0), AutoGenSeriesCollection = (1U << 1), AutoSizeChartMatrix = (1U << 2), } #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 Structs private struct Vector { public int Start; public int End; public bool IsEmpty { get { return (Start == End); } } } #endregion #region IDisposable public override void Dispose() { ChartContainers = null; ChartMatrix = null; ChartPanelVisualStyle = null; DefaultVisualStyles = null; base.Dispose(); } #endregion } #region enums #region ContainerLayout public enum ContainerLayout { Auto, Horizontal, Vertical, HorizontalThenVertical, VerticalThenHorizontal, } #endregion #region DividerLines /// /// Specifies which divider lines are displayed /// public enum DividerLines { /// /// Not set /// NotSet, /// /// No lines are displayed /// None, /// /// Only horizontal divider lines are displayed /// Horizontal, /// /// Only vertical divider lines are displayed /// Vertical, /// /// Both horizontal and vertical divider lines are displayed, /// horizontal first, then vertical. /// BothXy, /// /// Both horizontal and vertical divider lines are displayed /// vertical first, then horizontal. /// BothYx, } #endregion #region LegendSource [Flags] public enum LegendSource { None = 0, NestedCharts = (1 << 0), NestedPanels = (1 << 1), } #endregion #endregion #region BlankExpandableObjectConverter /// /// BlankExpandableObjectConverter /// public class BlankExpandableObjectConverter : ExpandableObjectConverter { /// /// ConvertTo /// /// /// /// /// /// public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) return (" "); return (base.ConvertTo(context, culture, value, destinationType)); } } #endregion }