Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web.DataVisualization / Common / Annotation / ArrowAnnotation.cs
1 //-------------------------------------------------------------
2 // <copyright company=\92Microsoft Corporation\92>
3 //   Copyright © Microsoft Corporation. All Rights Reserved.
4 // </copyright>
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 //  File:               ArrowAnnotation.cs
9 //
10 //  Namespace:  System.Web.UI.WebControls[Windows.Forms].Charting
11 //
12 //      Classes:        ArrowAnnotation
13 //
14 //  Purpose:    Arrow annotation classes.
15 //
16 //      Reviewed:       
17 //
18 //===================================================================
19
20 #region Used namespace
21 using System;
22 using System.Collections;
23 using System.Collections.Specialized;
24 using System.ComponentModel;
25 using System.ComponentModel.Design;
26 using System.Data;
27 using System.Drawing;
28 using System.Drawing.Design;
29 using System.Drawing.Text;
30 using System.Drawing.Drawing2D;
31 #if Microsoft_CONTROL
32 using System.Windows.Forms.DataVisualization.Charting;
33 using System.Windows.Forms.DataVisualization.Charting.Data;
34 using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
35 using System.Windows.Forms.DataVisualization.Charting.Utilities;
36 using System.Windows.Forms.DataVisualization.Charting.Borders3D;
37
38 #else
39 using System.Web;
40 using System.Web.UI;
41 using System.Web.UI.DataVisualization.Charting;
42 using System.Web.UI.DataVisualization.Charting.Data;
43 using System.Web.UI.DataVisualization.Charting.Utilities;
44 using System.Web.UI.DataVisualization.Charting.Borders3D;
45 #endif
46
47
48 #endregion
49
50 #if Microsoft_CONTROL
51 namespace System.Windows.Forms.DataVisualization.Charting
52
53 #else
54 namespace System.Web.UI.DataVisualization.Charting
55
56 #endif
57 {
58         #region Enumeration
59
60         /// <summary>
61         /// Arrow annotation styles.
62         /// <seealso cref="ArrowAnnotation.ArrowStyle"/>
63         /// </summary>
64         [
65         SRDescription("DescriptionAttributeArrowStyle_ArrowStyle")
66         ]
67         public enum ArrowStyle
68         {
69                 /// <summary>
70                 /// Simple arrow.
71                 /// </summary>
72                 Simple,
73
74                 /// <summary>
75                 /// Arrow pointing in two directions.
76                 /// </summary>
77                 DoubleArrow,
78
79                 /// <summary>
80                 /// Arrow with a tail.
81                 /// </summary>
82                 Tailed,
83         }
84
85         #endregion // Enumeration
86
87     /// <summary>
88     /// <b>ArrowAnnotation</b> is a class class that represents an arrow annotation.
89     /// </summary>
90     /// <remarks>
91     /// Arrow annotations can be used to connect to points on the chart or highlight a
92     /// single chart area. Different arrow styles and sizes may be applied.
93     /// </remarks>
94         [
95                 SRDescription("DescriptionAttributeArrowAnnotation_ArrowAnnotation"),
96         ]
97 #if ASPPERM_35
98         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
99     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
100 #endif
101         public class ArrowAnnotation : Annotation
102         {
103                 #region Fields
104
105                 // Annotation arrow style
106                 private         ArrowStyle              _arrowStyle = ArrowStyle.Simple;
107
108                 // Annotation arrow size
109                 private         int                             _arrowSize = 5;
110
111                 #endregion
112
113                 #region Construction and Initialization
114
115                 /// <summary>
116                 /// Default public constructor.
117                 /// </summary>
118                 public ArrowAnnotation() 
119             : base()
120                 {
121             base.AnchorAlignment = ContentAlignment.TopLeft;
122                 }
123
124                 #endregion
125
126                 #region Properties
127
128                 #region Arrow properties
129
130                 /// <summary>
131                 /// Gets or sets the arrow style of an arrow annotation.
132                 /// <seealso cref="ArrowSize"/>
133                 /// </summary>
134                 /// <value>
135                 /// <see cref="ArrowStyle"/> of an annotation.
136                 /// </value>
137                 [
138                 SRCategory("CategoryAttributeAppearance"),
139                 Bindable(true),
140                 DefaultValue(ArrowStyle.Simple),
141                 SRDescription("DescriptionAttributeArrowAnnotation_ArrowStyle"),
142                 ParenthesizePropertyNameAttribute(true),
143                 ]
144                 virtual public ArrowStyle ArrowStyle
145                 {
146                         get
147                         {
148                                 return _arrowStyle;
149                         }
150                         set
151                         {
152                                 _arrowStyle = value;
153                                 Invalidate();
154                         }
155                 }
156
157                 /// <summary>
158         /// Gets or sets the arrow size in pixels of an arrow annotation.
159                 /// <seealso cref="ArrowStyle"/>
160                 /// </summary>
161                 /// <value>
162                 /// Integer value that represents arrow size (thickness) in pixels.
163                 /// </value>
164                 [
165                 SRCategory("CategoryAttributeAppearance"),
166                 Bindable(true),
167                 DefaultValue(5),
168                 SRDescription("DescriptionAttributeArrowAnnotation_ArrowSize"),
169                 ParenthesizePropertyNameAttribute(true),
170                 ]
171                 virtual public int ArrowSize
172                 {
173                         get
174                         {
175                                 return _arrowSize;
176                         }
177                         set
178                         {
179                                 if(value <= 0)
180                                 {
181                                         throw(new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationArrowSizeIsZero));
182                                 }
183                                 if(value > 100)
184                                 {
185                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationArrowSizeMustBeLessThen100));
186                                 }
187                                 _arrowSize = value;
188                                 Invalidate();
189                         }
190                 }
191
192
193                 #endregion // Arrow properties
194
195                 #region Anchor
196
197                 /// <summary>
198         /// Gets or sets an annotation position's alignment to the anchor point.
199                 /// <seealso cref="Annotation.AnchorX"/>
200                 /// <seealso cref="Annotation.AnchorY"/>
201                 /// <seealso cref="Annotation.AnchorDataPoint"/>
202                 /// <seealso cref="Annotation.AnchorOffsetX"/>
203                 /// <seealso cref="Annotation.AnchorOffsetY"/>
204                 /// </summary>
205         /// <value>
206         /// A <see cref="ContentAlignment"/> value that represents the annotation's alignment to 
207         /// the anchor point.
208         /// </value>
209         /// <remarks>
210         /// The annotation must be anchored using either <see cref="Annotation.AnchorDataPoint"/>, or the <see cref="Annotation.AnchorX"/> 
211         /// and <see cref="Annotation.AnchorY"/> properties. Its <see cref="Annotation.X"/> and <see cref="Annotation.Y"/> 
212         /// properties must be set to <b>Double.NaN</b>.
213         /// </remarks>
214                 [
215                 SRCategory("CategoryAttributeAnchor"),
216                 Browsable(false),
217                 EditorBrowsableAttribute(EditorBrowsableState.Never),
218                 DefaultValue(typeof(ContentAlignment), "TopLeft"),
219                 SRDescription("DescriptionAttributeAnchorAlignment"),
220                 ]
221                 override public ContentAlignment AnchorAlignment
222                 {
223                         get
224                         {
225                                 return base.AnchorAlignment;
226                         }
227                         set
228                         {
229                                 base.AnchorAlignment = value;
230                         }
231                 }
232
233                 #endregion      // Anchoring
234
235                 #region Other
236
237         /// <summary>
238         /// Gets or sets an annotation's type name.
239         /// </summary>
240         /// <remarks>
241         /// This property is used to get the name of each annotation type  
242         /// (e.g. Line, Rectangle, Ellipse). 
243         /// <para>
244         /// This property is for internal use and is hidden at design and run time.
245         /// </para>
246         /// </remarks>
247                 [
248                 SRCategory("CategoryAttributeMisc"),
249                 Bindable(true),
250                 Browsable(false),
251                 EditorBrowsableAttribute(EditorBrowsableState.Never),
252                 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
253                 SerializationVisibilityAttribute(SerializationVisibility.Hidden),
254                 SRDescription("DescriptionAttributeAnnotationType"),
255                 ]
256                 public override string AnnotationType
257                 {
258                         get
259                         {
260                                 return "Arrow";
261                         }
262                 }
263
264                 /// <summary>
265                 /// Gets or sets annotation selection points style.
266                 /// </summary>
267                 /// <value>
268                 /// A <see cref="SelectionPointsStyle"/> value that represents annotation
269                 /// selection style.
270                 /// </value>
271                 /// <remarks>
272         /// This property is for internal use and is hidden at design and run time.
273                 /// </remarks>
274                 [
275                 SRCategory("CategoryAttributeAppearance"),
276                 DefaultValue(SelectionPointsStyle.Rectangle),
277                 ParenthesizePropertyNameAttribute(true),
278                 Browsable(false),
279                 EditorBrowsableAttribute(EditorBrowsableState.Never),
280                 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
281                 SerializationVisibilityAttribute(SerializationVisibility.Hidden),
282                 SRDescription("DescriptionAttributeSelectionPointsStyle"),
283                 ]
284                 override internal SelectionPointsStyle SelectionPointsStyle
285                 {
286                         get
287                         {
288                                 return SelectionPointsStyle.TwoPoints;
289                         }
290                 }
291
292                 #endregion
293
294                 #endregion
295
296                 #region Methods
297
298                 /// <summary>
299                 /// Paints annotation object on specified graphics.
300                 /// </summary>
301                 /// <param name="graphics">
302                 /// A <see cref="ChartGraphics"/> used to paint annotation object.
303                 /// </param>
304                 /// <param name="chart">
305                 /// Reference to the <see cref="Chart"/> control.
306                 /// </param>
307         override internal void Paint(Chart chart, ChartGraphics graphics)
308                 {
309                         // Get annotation position in relative coordinates
310                         PointF firstPoint = PointF.Empty;
311                         PointF anchorPoint = PointF.Empty;
312                         SizeF size = SizeF.Empty;
313                         GetRelativePosition(out firstPoint, out size, out anchorPoint);
314                         PointF  secondPoint = new PointF(firstPoint.X + size.Width, firstPoint.Y + size.Height);
315
316                         // Create selection rectangle
317                         RectangleF selectionRect = new RectangleF(firstPoint, new SizeF(secondPoint.X - firstPoint.X, secondPoint.Y - firstPoint.Y));
318
319                         // Check if text position is valid
320                         if( float.IsNaN(firstPoint.X) || 
321                                 float.IsNaN(firstPoint.Y) || 
322                                 float.IsNaN(secondPoint.X) || 
323                                 float.IsNaN(secondPoint.Y) )
324                         {
325                                 return;
326                         }
327
328                         // Get arrow shape path
329             using (GraphicsPath arrowPathAbs = GetArrowPath(graphics, selectionRect))
330             {
331
332                 // Draw arrow shape
333                 if (this.Common.ProcessModePaint)
334                 {
335                     graphics.DrawPathAbs(
336                         arrowPathAbs,
337                         (this.BackColor.IsEmpty) ? Color.White : this.BackColor,
338                         this.BackHatchStyle,
339                         String.Empty,
340                         ChartImageWrapMode.Scaled,
341                         Color.Empty,
342                         ChartImageAlignmentStyle.Center,
343                         this.BackGradientStyle,
344                         this.BackSecondaryColor,
345                         this.LineColor,
346                         this.LineWidth,
347                         this.LineDashStyle,
348                         PenAlignment.Center,
349                         this.ShadowOffset,
350                         this.ShadowColor);
351                 }
352
353                 // Process hot region
354                 if (this.Common.ProcessModeRegions)
355                 {
356                     // Use callout defined hot region
357                     this.Common.HotRegionsList.AddHotRegion(
358                         graphics,
359                         arrowPathAbs,
360                         false,
361                         ReplaceKeywords(this.ToolTip),
362 #if Microsoft_CONTROL
363                                         String.Empty,
364                                         String.Empty,
365                                         String.Empty,
366 #else // Microsoft_CONTROL
367                     ReplaceKeywords(this.Url),
368                                 ReplaceKeywords(this.MapAreaAttributes),
369                     ReplaceKeywords(this.PostBackValue),
370 #endif // Microsoft_CONTROL
371  this,
372                         ChartElementType.Annotation);
373                 }
374
375                 // Paint selection handles
376                 PaintSelectionHandles(graphics, selectionRect, null);
377             }
378                 }
379
380                 /// <summary>
381                 /// Get arrow path for the specified annotation position
382                 /// </summary>
383                 /// <param name="graphics"></param>
384                 /// <param name="position"></param>
385                 /// <returns></returns>
386                 private GraphicsPath GetArrowPath(
387                         ChartGraphics graphics,
388                         RectangleF position)
389                 {
390                         // Get absolute position
391                         RectangleF positionAbs = graphics.GetAbsoluteRectangle(position);
392                         PointF firstPoint = positionAbs.Location;
393                         PointF secondPoint = new PointF(positionAbs.Right, positionAbs.Bottom);
394
395                         // Calculate arrow length
396                         float deltaX = secondPoint.X - firstPoint.X;
397                         float deltaY = secondPoint.Y - firstPoint.Y;
398                         float arrowLength = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
399
400                         // Create unrotated graphics path for the arrow started at the annotation location
401                         // and going to the right for the length of the rotated arrow.
402                         GraphicsPath path = new GraphicsPath();
403
404                         PointF[]        points = null;
405                         float           pointerRatio = 2.1f;
406                         if(this.ArrowStyle == ArrowStyle.Simple)
407                         {
408                                 points = new PointF[] {
409                                                                                   firstPoint,
410                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize*pointerRatio),
411                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize),
412                                                                                   new PointF(firstPoint.X + arrowLength, firstPoint.Y - this.ArrowSize),
413                                                                                   new PointF(firstPoint.X + arrowLength, firstPoint.Y + this.ArrowSize),
414                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize),
415                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize*pointerRatio) };
416                         }
417                         else if(this.ArrowStyle == ArrowStyle.DoubleArrow)
418                         {
419                                 points = new PointF[] {
420                                                                                   firstPoint,
421                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize*pointerRatio),
422                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize),
423                                                                                   new PointF(firstPoint.X + arrowLength - this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize),
424                                                                                   new PointF(firstPoint.X + arrowLength - this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize*pointerRatio),
425                                                                                   new PointF(firstPoint.X + arrowLength, firstPoint.Y),
426                                                                                   new PointF(firstPoint.X + arrowLength - this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize*pointerRatio),
427                                                                                   new PointF(firstPoint.X + arrowLength - this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize),
428                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize),
429                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize*pointerRatio) };
430                         }
431                         else if(this.ArrowStyle == ArrowStyle.Tailed)
432                         {
433                                 float           tailRatio = 2.1f;
434                                 points = new PointF[] {
435                                                                                   firstPoint,
436                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize*pointerRatio),
437                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y - this.ArrowSize),
438                                                                                   new PointF(firstPoint.X + arrowLength, firstPoint.Y - this.ArrowSize*tailRatio),
439                                                                                   new PointF(firstPoint.X + arrowLength - this.ArrowSize*tailRatio, firstPoint.Y),
440                                                                                   new PointF(firstPoint.X + arrowLength, firstPoint.Y + this.ArrowSize*tailRatio),
441                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize),
442                                                                                   new PointF(firstPoint.X + this.ArrowSize*pointerRatio, firstPoint.Y + this.ArrowSize*pointerRatio) };
443                         }
444                         else
445                         {
446                 throw (new InvalidOperationException(SR.ExceptionAnnotationArrowStyleUnknown));
447                         }
448
449                         path.AddLines(points);
450                         path.CloseAllFigures();
451
452                         // Calculate arrow angle
453                         float angle = (float)(Math.Atan(deltaY / deltaX) * 180f / Math.PI);
454                         if(deltaX < 0)
455                         {
456                                 angle += 180f;
457                         }
458
459                         // Rotate arrow path around the first point
460                         using( Matrix matrix = new Matrix() )
461                         {
462                                 matrix.RotateAt(angle, firstPoint);
463                                 path.Transform(matrix);
464                         }
465
466                         return path;
467                 }
468
469                 #endregion
470         }
471 }