// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // // Purpose: Design-time UI editor for Annotations. // #if DESIGNER using System.ComponentModel; using System.Drawing.Design; using System.Globalization; using FastReport.DataVisualization.Charting; namespace FastReport.Design.DataVisualization.Charting { /// /// Designer editor for the Annotation Collection. /// internal class AnnotationCollectionEditor : ChartCollectionEditor { #region Methods /// /// Object constructor. /// public AnnotationCollectionEditor() : base(typeof(AnnotationCollection)) { } /// /// Gets the data types that this collection editor can contain. /// /// An array of data types that this collection can contain. protected override Type[] CreateNewItemTypes() { return new Type[] { typeof(LineAnnotation), typeof(VerticalLineAnnotation), typeof(HorizontalLineAnnotation), typeof(TextAnnotation), typeof(RectangleAnnotation), typeof(EllipseAnnotation), typeof(ArrowAnnotation), typeof(Border3DAnnotation), typeof(CalloutAnnotation), typeof(PolylineAnnotation), typeof(PolygonAnnotation), typeof(ImageAnnotation), typeof(AnnotationGroup) }; } /// /// Create annotation instance in the editor /// /// Item type. /// Newly created item. protected override object CreateInstance(Type itemType) { Chart control = (Chart)GetChartReference(Context.Instance); // Call base class Annotation annotation = base.CreateInstance(itemType) as Annotation; // Generate unique name if (control != null) { annotation.Name = NextUniqueName(control, itemType); } return annotation; } /// /// Finds the unique name for a new annotation being added to the collection /// /// Chart control reference. /// Type of the annotation added. /// Next unique chart annotation name private static string NextUniqueName(Chart control, Type type) { // Find unique name string result = string.Empty; string prefix = type.Name; for (int i = 1; i < System.Int32.MaxValue; i++) { result = prefix + i.ToString(CultureInfo.InvariantCulture); // Check whether the name is unique if (control.Annotations.IsUniqueName(result)) { break; } } return result; } #endregion // Methods } /// /// UI type editor for the annotation anchor point /// internal class AnchorPointUITypeEditor : System.Drawing.Design.UITypeEditor { #region Editor methods and properties /// /// Display a drop down list with check boxes. /// /// Editing context. /// Provider. /// Value to edit. /// Result public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { if (context != null && context.Instance != null && provider != null) { IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc != null && context.Instance is Annotation) { // Create control for editing AnchorPointNameTreeView control = new AnchorPointNameTreeView( edSvc, (Annotation)context.Instance, value as DataPoint); // Show drop down control edSvc.DropDownControl(control); // Get new enumeration value value = control.GetNewValue(); // Dispose control control.Dispose(); } } return value; } /// /// Gets editing style. /// /// Editing context. /// Editor style. public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { if (context != null && context.Instance != null) { return UITypeEditorEditStyle.DropDown; } return base.GetEditStyle(context); } #endregion } /// /// Anchor data points name tree view, which is used for the UI type editing. /// internal class AnchorPointNameTreeView : TreeView { #region Control fields // Annotation object to edit private Annotation _annotation = null; private DataPoint _dataPoint = null; IWindowsFormsEditorService _edSvc = null; #endregion #region Control constructor /// /// Public constructor. /// /// Editor service. /// Annotation to edit. /// Annotation anchor data point to edit. public AnchorPointNameTreeView( IWindowsFormsEditorService edSvc, Annotation annotation, DataPoint dataPoint) { // Set editable value this._annotation = annotation; this._dataPoint = dataPoint; this._edSvc = edSvc; // Set control border style this.BorderStyle = BorderStyle.None; // Fill tree with data point names this.FillTree(); } #endregion #region Control methods /// /// Fills data points name tree. /// private void FillTree() { bool nodeSelected = false; this.BeginUpdate(); // Add "None" option TreeNode noPoint = this.Nodes.Add("NotSet"); // Get chart object if (this._annotation != null && _annotation.AnnotationGroup == null && this._annotation.Chart != null) { Chart chart = this._annotation.Chart; // Loop through all series foreach (Series series in chart.Series) { TreeNode seriesNode = this.Nodes.Add(series.Name); seriesNode.Tag = series; // Indicate that there are no points in series if (series.Points.Count == 0) { seriesNode.Nodes.Add("(empty)"); } // Loop through all points int index = 1; foreach (DataPoint point in series.Points) { TreeNode dataPointNode = seriesNode.Nodes.Add("DataPoint" + index.ToString(System.Globalization.CultureInfo.InvariantCulture)); dataPointNode.Tag = point; ++index; // Check if this node should be selected if (point == _dataPoint) { seriesNode.Expand(); this.SelectedNode = dataPointNode; nodeSelected = true; } } } } // Select default node if (!nodeSelected) { this.SelectedNode = noPoint; } this.EndUpdate(); } /// /// Gets new data point. /// /// New enum value. public DataPoint GetNewValue() { if (this.SelectedNode != null && this.SelectedNode.Tag != null && this.SelectedNode.Tag is DataPoint) { return (DataPoint)this.SelectedNode.Tag; } return null; } /// /// Mouse double clicked. /// protected override void OnDoubleClick(EventArgs e) { base.OnDoubleClick(e); if (this._edSvc != null) { if (GetNewValue() != null) { this._edSvc.CloseDropDown(); } else if (this.SelectedNode != null && this.SelectedNode.Text == "NotSet") { this._edSvc.CloseDropDown(); } } } #endregion } /// /// UI type editor for the annotation axes. /// internal class AnnotationAxisUITypeEditor : System.Drawing.Design.UITypeEditor { #region Editor methods and properties /// /// Display a drop down list with check boxes. /// /// Editing context. /// Provider. /// Value to edit. /// Result public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { if (context != null && context.Instance != null && provider != null) { IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc != null && context.Instance is Annotation) { // Check if we dealing with X or Y axis bool showXAxes = true; if (context.PropertyDescriptor != null && context.PropertyDescriptor.Name == "AxisY") { showXAxes = false; } // Create control for editing AnnotationAxisNameTreeView control = new AnnotationAxisNameTreeView( edSvc, (Annotation)context.Instance, value as Axis, showXAxes); // Show drop down control edSvc.DropDownControl(control); // Get new enumeration value value = control.GetNewValue(); // Dispose control control.Dispose(); } } return value; } /// /// Gets editing style. /// /// Editing context. /// Editor style. public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { if (context != null && context.Instance != null) { return UITypeEditorEditStyle.DropDown; } return base.GetEditStyle(context); } #endregion } /// /// Annotation axes names tree view, which is used for the UI type editing. /// internal class AnnotationAxisNameTreeView : TreeView { #region Control fields // Annotation object to edit private Annotation _annotation = null; private Axis _axis = null; IWindowsFormsEditorService _edSvc = null; private bool _showXAxes = true; #endregion #region Control constructor /// /// Public constructor. /// /// Editor service. /// Annotation to edit. /// Axis object. /// Indicates if X or Y axis should be shown. public AnnotationAxisNameTreeView( IWindowsFormsEditorService edSvc, Annotation annotation, Axis axis, bool showXAxes) { // Set editable value this._annotation = annotation; this._axis = axis; this._edSvc = edSvc; this._showXAxes = showXAxes; // Set control border style this.BorderStyle = BorderStyle.None; // Fill tree with data point names this.FillTree(); } #endregion #region Control methods /// /// Fills data points name tree. /// private void FillTree() { bool nodeSelected = false; this.BeginUpdate(); // Add "None" option TreeNode noPoint = this.Nodes.Add("NotSet"); // Get chart object if (this._annotation != null && _annotation.AnnotationGroup == null && this._annotation.Chart != null) { Chart chart = this._annotation.Chart; // Loop through all chart areas foreach (ChartArea chartArea in chart.ChartAreas) { TreeNode areaNode = this.Nodes.Add(chartArea.Name); areaNode.Tag = chartArea; // Loop through all axes foreach (Axis curAxis in chartArea.Axes) { // Hide X or Y axes if (curAxis.AxisName == AxisName.Y || curAxis.AxisName == AxisName.Y2) { if (_showXAxes) { continue; } } if (curAxis.AxisName == AxisName.X || curAxis.AxisName == AxisName.X2) { if (!_showXAxes) { continue; } } // Create child node TreeNode axisNode = areaNode.Nodes.Add(curAxis.Name); axisNode.Tag = curAxis; // Check if this node should be selected if (_axis == curAxis) { areaNode.Expand(); this.SelectedNode = axisNode; nodeSelected = true; } } } } // Select default node if (!nodeSelected) { this.SelectedNode = noPoint; } this.EndUpdate(); } /// /// Gets new data point. /// /// New enum value. public Axis GetNewValue() { if (this.SelectedNode != null && this.SelectedNode.Tag != null && this.SelectedNode.Tag is Axis) { return (Axis)this.SelectedNode.Tag; } return null; } /// /// Mouse double clicked. /// protected override void OnDoubleClick(EventArgs e) { base.OnDoubleClick(e); if (this._edSvc != null) { if (GetNewValue() != null) { this._edSvc.CloseDropDown(); } else if (this.SelectedNode != null && this.SelectedNode.Text == "NotSet") { this._edSvc.CloseDropDown(); } } } #endregion } } #endif