Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web.DataVisualization / Common / General / Legend.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:               Legend.cs
9 //
10 //  Namespace:  DataVisualization.Charting
11 //
12 //      Classes:        Legend, LegendCollection, LegendItemsCollection, 
13 //              LegendItem
14 //
15 //  Purpose:    Chart Legend consist of default and custom legend 
16 //              items. Default items are automatically added based
17 //              on the data series and custom items are added by
18 //              the user. Each item usually consist of 2 cells; 
19 //              series color marker and series name. Legend item 
20 //              cells form vertical columns in the legend.
21 //  
22 //              Please refer to the Chart documentation which 
23 //              contains images and samples describing legend features.
24 //
25 //  NOTE: In early versions of the Chart control only 1 legend was 
26 //  exposed through the Legend property of the root chart object. 
27 //  Due to the customer requests, support for unlimited number of 
28 //  legends was added through the LegendCollection exposed as a 
29 //  Legends property in the root chart object. Old propertys was 
30 //  deprecated and marked as non-browsable. 
31 //
32 //      Reviewed:       AG - Jul 31, 2002; 
33 //              GS - Aug 7, 2002
34 //              AG - Microsoft 14, 2007
35 //
36 //===================================================================
37
38 #region Used namespaces
39
40 using System;
41 using System.Collections;
42 using System.Collections.Specialized;
43 using System.Collections.Generic;
44 using System.ComponentModel;
45 using System.ComponentModel.Design;
46 using System.Data;
47 using System.Drawing;
48 using System.Drawing.Design;
49 using System.Drawing.Drawing2D;
50 using System.Globalization;
51 using System.Diagnostics.CodeAnalysis;
52
53 #if Microsoft_CONTROL
54         using System.Windows.Forms.DataVisualization.Charting.Data;
55         using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
56         using System.Windows.Forms.DataVisualization.Charting.Utilities;
57         using System.Windows.Forms.DataVisualization.Charting.Borders3D;
58         using System.Windows.Forms.DataVisualization.Charting;
59         using System.ComponentModel.Design.Serialization;
60         using System.Reflection;
61         using System.Windows.Forms.Design;
62 #else
63         using System.Web;
64         using System.Web.UI;
65         using System.Web.UI.DataVisualization.Charting;
66         using System.Web.UI.DataVisualization.Charting.Data;
67         using System.Web.UI.DataVisualization.Charting.Utilities;
68         using System.Web.UI.DataVisualization.Charting.ChartTypes;
69 #endif
70
71
72 #endregion
73
74 #if Microsoft_CONTROL
75         namespace System.Windows.Forms.DataVisualization.Charting
76 #else
77 namespace System.Web.UI.DataVisualization.Charting
78
79 #endif
80 {
81         #region Legend enumerations
82
83     /// <summary>
84     /// An enumeration of legend item orderings.
85     /// </summary>
86     public enum LegendItemOrder
87     {
88         /// <summary>
89         /// Items will be added into the legend in an order automatically determined by the chart.
90         /// </summary>
91         Auto,
92
93         /// <summary>
94         /// Items will be added into the legend in the same order as the chart series.
95         /// </summary>
96         SameAsSeriesOrder,
97
98         /// <summary>
99         /// Items will be added into the legend in the same order as the chart series.
100         /// </summary>
101         ReversedSeriesOrder
102
103     };
104
105         /// <summary>
106         /// An enumeration of legend separator styles.
107         /// </summary>
108         public enum LegendSeparatorStyle
109         {
110                 /// <summary>
111                 /// No separator will be shown.
112                 /// </summary>
113                 None,
114
115         /// <summary>
116         /// Single solid line separator.
117         /// </summary>
118                 Line,
119
120         /// <summary>
121         /// Single solid thick line separator.
122         /// </summary>
123                 ThickLine,
124
125                 /// <summary>
126                 /// Double solid line separator.
127                 /// </summary>
128                 DoubleLine,
129
130                 /// <summary>
131                 /// Single dash line separator.
132                 /// </summary>
133                 DashLine,
134
135                 /// <summary>
136                 /// Single dot line separator.
137                 /// </summary>
138                 DotLine,
139
140                 /// <summary>
141                 /// Gradient solid line separator.
142                 /// </summary>
143                 GradientLine,
144
145                 /// <summary>
146                 /// Thick gradient solid line separator.
147                 /// </summary>
148                 ThickGradientLine,
149         }
150
151
152
153         /// <summary>
154     /// An enumeration that specifies a style for a legend item's symbol.
155         /// </summary>
156         public enum LegendImageStyle
157         {
158                 /// <summary>
159         /// The symbol will be a rectangle.
160                 /// </summary>
161                 Rectangle, 
162
163                 /// <summary>
164         /// The symbol will be a line.
165                 /// </summary>
166                 Line, 
167
168                 /// <summary>
169         /// The symbol will be a marker.
170                 /// </summary>
171                 Marker
172         }
173
174         /// <summary>
175         /// An enumeration of legend styles.
176         /// </summary>
177         public enum LegendStyle
178         {
179                 /// <summary>
180                 /// One column, many rows.
181                 /// </summary>
182                 Column, 
183
184                 /// <summary>
185                 /// One row, many columns.
186                 /// </summary>
187                 Row, 
188
189                 /// <summary>
190                 /// Many column, many rows.
191                 /// </summary>
192                 Table
193         };
194
195         /// <summary>
196         /// An enumeration of legend table styles.
197         /// </summary>
198         public enum LegendTableStyle
199         {
200                 /// <summary>
201         /// The legend table style is automatically determined by the chart.
202                 /// </summary>
203                 Auto, 
204
205                 /// <summary>
206         /// The legend items will be fit horizontally within the legend.  
207         /// It is preferred to use this style when the docking is set to top or bottom.
208                 /// </summary>
209                 Wide, 
210
211                 /// <summary>
212         /// The legend items will be fit vertically within the legend.  
213         /// It is preferred to use this style when docking is set to left or right.
214                 /// </summary>
215                 Tall
216         };
217         
218         #endregion
219
220     /// <summary>
221     /// The legend class represents a single chart legend. It contains visual
222     /// appearance, position and content properties. This class is also 
223     /// responsible for drawing and positioning of the legend.
224     /// </summary>
225         [
226         SRDescription("DescriptionAttributeLegend_Legend"),
227         DefaultProperty("Enabled"),
228         ]
229 #if ASPPERM_35
230         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
231     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
232 #endif
233     public class Legend : ChartNamedElement
234         {
235             #region Fields
236
237         //***********************************************************
238                 //** Private data members, which store properties values
239                 //***********************************************************
240                 private ElementPosition                 _position = null;
241                 private bool                                    _enabled = true;
242
243                 private LegendStyle                             _legendStyle = LegendStyle.Table;
244
245                 private LegendTableStyle                _legendTableStyle = LegendTableStyle.Auto;
246                 private LegendItemsCollection   _customLegends = null;
247                 private ChartHatchStyle                 _backHatchStyle = ChartHatchStyle.None;
248                 private string                                  _backImage = "";
249                 private ChartImageWrapMode              _backImageWrapMode = ChartImageWrapMode.Tile;
250                 private Color                                   _backImageTransparentColor = Color.Empty;
251                 private ChartImageAlignmentStyle        _backImageAlignment = ChartImageAlignmentStyle.TopLeft;
252                 private GradientStyle                   _backGradientStyle = GradientStyle.None;
253                 private Color                                   _backSecondaryColor = Color.Empty;
254                 private Color                                   _borderColor = Color.Empty;
255                 private Color                                   _backColor = Color.Empty;
256                 private int                                             _borderWidth = 1;
257                 private ChartDashStyle                  _borderDashStyle = ChartDashStyle.Solid;
258         private FontCache               _fontCache = new FontCache();
259         private Font                    _font = null;
260                 private Color                                   _foreColor = Color.Black;
261                 private StringAlignment                 _legendAlignment = StringAlignment.Near;
262                 private Docking                         _legendDocking = Docking.Right;
263                 private int                                             _shadowOffset = 0;
264                 private Color                                   _shadowColor = Color.FromArgb(128, 0, 0, 0);
265                 private bool                                    _isTextAutoFit = true;
266         private string                  _dockedToChartArea = Constants.NotSetValue;
267                 private bool                                    _isDockedInsideChartArea = true;
268
269                 //***********************************************************
270                 //** Private data members
271                 //***********************************************************
272
273                 // Collection of custom and series legend items
274                 internal LegendItemsCollection  legendItems = null;
275
276                 // Number of rows and columns
277                 private int             _itemColumns = 0;
278
279
280                 // Font calculated by auto fitting
281                 internal Font   autofitFont = null;
282
283                 // Indicates that all items in the legend should be equally spaced
284                 private bool    _isEquallySpacedItems = false;
285
286
287                 // Indicate that legend rows should be drawn with isInterlaced background color.
288                 private bool            _interlacedRows = false;
289
290                 // Legend isInterlaced rows color
291                 private Color           _interlacedRowsColor = Color.Empty;
292
293                 // Legend offsets
294                 private Size            _offset = Size.Empty;
295
296                 // Adjustment point used for legend animation
297                 private float           _maximumLegendAutoSize = 50f;
298
299                 // Text length after which the legend item text will be wrapped on the next whitespace.
300                 private int                     _textWrapThreshold = 25;
301
302                 // Value used to calculate auto-fit font size from the legend Font.
303                 private int                     _autoFitFontSizeAdjustment = 0;
304
305                 // Legend column collection
306                 private LegendCellColumnCollection _cellColumns = null;
307
308                 // Indicates that legend items automatically added based on the exsisting 
309                 // series in reversed order.
310         private LegendItemOrder _legendItemOrder = LegendItemOrder.Auto;
311
312                 // Legend title text
313                 private string          _title = String.Empty;
314
315                 // Legend title color
316                 private Color           _titleForeColor = Color.Black;
317
318                 // Legend title back color
319                 private Color           _titleBackColor = Color.Empty;
320
321                 // Legend title font
322                 private Font            _titleFont = null;
323
324                 // Legend title alignment
325                 private StringAlignment         _titleAlignment = StringAlignment.Center;
326
327                 // Legend title visual separator
328                 private LegendSeparatorStyle    _titleSeparator = LegendSeparatorStyle.None;
329
330                 // Legend title visual separator color
331                 private Color           _titleSeparatorColor = Color.Black;
332
333                 // Legend header visual separator
334                 private LegendSeparatorStyle    _headerSeparator = LegendSeparatorStyle.None;
335
336                 // Legend header visual separator color
337                 private Color           _headerSeparatorColor = Color.Black;
338
339                 // Legend table columns visual separator
340                 private LegendSeparatorStyle    _itemColumnSeparator = LegendSeparatorStyle.None;
341
342                 // Legend table columns visual separator color
343                 private Color           _itemColumnSeparatorColor = Color.Black;
344
345                 // Legend table column spacing calculated as a percentage of the font
346                 private int                     _itemColumnSpacing = 50;
347
348                 // Legend table column spacing calculated in relative coordinates
349                 private int             _itemColumnSpacingRel = 0;
350
351                 // Legend title position in pixelcoordinates.
352                 // Note that legend title always docked to the top of the legend.
353                 private Rectangle       _titlePosition = Rectangle.Empty;
354
355                 // Legend header position in pixel coordinates.
356                 private Rectangle       _headerPosition = Rectangle.Empty;
357
358                 // Minimum font size that can be used by the legend auto-fitting algorithm
359                 private int                     _autoFitMinFontSize = 7;
360
361                 // Horizontal space left after fitting legend items
362                 private int             _horizontalSpaceLeft = 0;
363
364                 // Vertical space left after fitting legend items
365                 private int             _verticalSpaceLeft = 0;
366
367                 // Sub-columns sizes calculated during the fitting process
368                 private int[,]  _subColumnSizes = null;
369
370                 // Legend item heigts
371                 private int[,]  _cellHeights = null;
372
373                 // Number of rows per each legend table column
374                 private int[]           _numberOfRowsPerColumn = null;
375
376                 // Number of items from the collection that should be processed
377                 private int                     _numberOfLegendItemsToProcess = -1;
378
379                 // Legend items area position in pixels
380                 private Rectangle       _legendItemsAreaPosition = Rectangle.Empty;
381
382                 // Indicates that not all legend items were able to fit the legend
383                 private bool            _legendItemsTruncated = false;
384
385                 // Size of the dots (pixels) that will drawn on the bottom of the legend when it is truncated
386                 private int                     _truncatedDotsSize = 3;
387
388                 // Maximum number of cells in the legend item
389                 private int                     _numberOfCells = -1;
390
391                 // Pixel size of the 'W' character
392                 internal Size           singleWCharacterSize = Size.Empty;
393
394
395                 #endregion
396
397                 #region Constructors
398
399                 /// <summary>
400                 /// Legend constructor
401                 /// </summary>
402                 public Legend()
403                 {
404             _position = new ElementPosition(this);
405             // Initialize custom items collection
406                         _customLegends = new LegendItemsCollection(this);
407                         legendItems = new LegendItemsCollection(this);
408                         _cellColumns = new LegendCellColumnCollection(this);
409             _font = _fontCache.DefaultFont;
410             _titleFont = _fontCache.DefaultBoldFont;
411                 }
412
413         /// <summary>
414         /// Legend constructor
415         /// </summary>
416         /// <param name="name">The legend name.</param>
417         public Legend(string name) : base (name)
418         {
419             _position = new ElementPosition(this);
420             // Initialize custom items collection
421             _customLegends = new LegendItemsCollection(this);
422             legendItems = new LegendItemsCollection(this);
423             _cellColumns = new LegendCellColumnCollection(this);
424             _font = _fontCache.DefaultFont;
425             _titleFont = _fontCache.DefaultBoldFont;
426         }
427
428                 #endregion
429
430                 #region Legend position & size methods
431
432                 /// <summary>
433                 /// Recalculates legend information:
434                 ///   - legend items collection
435                 ///   - maximum text rectangle
436                 /// </summary>
437                 /// <param name="chartGraph">Reference to the chart graphics.</param>
438                 private void RecalcLegendInfo(ChartGraphics chartGraph)
439                 {
440                         // Reset some values
441                         RectangleF      legendPositionRel = _position.ToRectangleF();
442                         Rectangle       legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(legendPositionRel));
443
444                         //***********************************************************
445                         //** Use size of the "W" characters in current font to 
446                         //** calculate legend spacing
447                         //***********************************************************
448                         this.singleWCharacterSize =  chartGraph.MeasureStringAbs("W", this.Font);
449                         Size doubleCharacterSize =  chartGraph.MeasureStringAbs("WW", this.Font);
450                         this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
451                         
452                         // Calculate left, top offset and column spacing
453                         this._offset.Width = (int)Math.Ceiling(singleWCharacterSize.Width / 2f);
454                         this._offset.Height = (int)Math.Ceiling(singleWCharacterSize.Width / 3f);
455
456                         // Calculate item column spacing and make sure it is dividable by 2
457                         this._itemColumnSpacingRel = (int)(singleWCharacterSize.Width * (this._itemColumnSpacing / 100f));
458                         if(this._itemColumnSpacingRel % 2 == 1)
459                         {
460                                 this._itemColumnSpacingRel += 1;
461                         }
462
463                         //***********************************************************
464                         //** Calculate how much space required for the title.
465                         //***********************************************************
466                         this._titlePosition = Rectangle.Empty;
467                         if(this.Title.Length > 0)
468                         {
469                                 // Measure title text size
470                                 Size titleSize = this.GetTitleSize(chartGraph, legendPosition.Size);
471
472                                 // Set legend title position
473                                 this._titlePosition = new Rectangle(
474                                         legendPosition.Location.X,
475                                         legendPosition.Location.Y,
476                                         legendPosition.Width,
477                                         Math.Min(legendPosition.Height, titleSize.Height));
478
479                                 // Adjust legend items position height
480                                 legendPosition.Height -= this._titlePosition.Height;
481
482                                 // Increase title top location by border height
483                                 this._titlePosition.Y += this.GetBorderSize();
484                         }
485
486
487                         //***********************************************************
488                         //** Calculate how much space required for the header.
489                         //***********************************************************
490                         this._headerPosition = Rectangle.Empty;
491
492                         // Find the largest (height only) header
493                         Size highestHeader = Size.Empty;
494                         foreach(LegendCellColumn legendColumn in this.CellColumns)
495                         {
496                                 if(legendColumn.HeaderText.Length > 0)
497                                 {
498                                         // Measure header text size
499                                         Size headerSize = this.GetHeaderSize(chartGraph, legendColumn);
500
501                                         // Get header with maximum height
502                                         highestHeader.Height = Math.Max(highestHeader.Height, headerSize.Height);
503                                 }
504                         }
505
506                         // Check if any headers where found
507                         if(!highestHeader.IsEmpty)
508                         {
509                                 // Set legend header position
510                                 this._headerPosition = new Rectangle(
511                                         legendPosition.Location.X + this.GetBorderSize() + this._offset.Width,
512                                         legendPosition.Location.Y + this._titlePosition.Height,
513                                         legendPosition.Width - (this.GetBorderSize() + this._offset.Width) * 2,
514                                         Math.Min(legendPosition.Height - this._titlePosition.Height, highestHeader.Height));
515                                 this._headerPosition.Height = Math.Max(this._headerPosition.Height, 0);
516
517                                 // Adjust legend items position height
518                                 legendPosition.Height -= this._headerPosition.Height;
519
520                                 // Increase header top location by border height
521                                 this._headerPosition.Y += this.GetBorderSize();
522                         }
523
524
525                         //***********************************************************
526                         //** Calculate size available for all legend items
527                         //***********************************************************
528                         this._legendItemsAreaPosition = new Rectangle(
529                                 legendPosition.X + this._offset.Width + this.GetBorderSize(),
530                                 legendPosition.Y + this._offset.Height + this.GetBorderSize() + this._titlePosition.Height + this._headerPosition.Height,
531                                 legendPosition.Width - 2 * (this._offset.Width + this.GetBorderSize()),
532                                 legendPosition.Height - 2 * (this._offset.Height + this.GetBorderSize()) );
533
534                         //***********************************************************
535                         //** Calculate number of rows and columns depending on
536                         //** the legend style
537                         //***********************************************************
538                         this.GetNumberOfRowsAndColumns(
539                                 chartGraph, 
540                                 this._legendItemsAreaPosition.Size,
541                                 -1,
542                                 out this._numberOfRowsPerColumn, 
543                                 out this._itemColumns,
544                                 out this._horizontalSpaceLeft,
545                                 out this._verticalSpaceLeft);
546
547                         //***********************************************************
548                         //** Try to fit all legend item cells reducing the font size
549                         //***********************************************************
550
551                         // Reset auto-fit font adjustment value and truncated legend flag
552                         this._autoFitFontSizeAdjustment = 0;
553                         this._legendItemsTruncated = false;
554
555                         // Check if legend items fit into the legend area
556                         bool autoFitDone = (this._horizontalSpaceLeft >= 0 && this._verticalSpaceLeft >= 0);
557
558                         // Calculate total number of items fit and make sure we fit all of them
559                         this._numberOfLegendItemsToProcess = this.legendItems.Count;
560                         int itemsFit = 0;
561                         for(int index = 0; index < this._itemColumns; index++)
562                         {
563                                 itemsFit += this._numberOfRowsPerColumn[index];
564                         }
565                         if(itemsFit < this._numberOfLegendItemsToProcess)
566                         {
567                                 autoFitDone = false;
568                         }
569
570             // If items do not fit try reducing font or number of legend items
571             this.autofitFont = this.Font;
572                         if(!autoFitDone)
573                         {
574                                 do
575                                 {
576                                         // Check if legend item font size can be reduced
577                                         if(this.IsTextAutoFit && 
578                                                 (this.Font.Size - this._autoFitFontSizeAdjustment) > this._autoFitMinFontSize)
579                                         {
580                                                 // Reduce font size by one 
581                                                 ++this._autoFitFontSizeAdjustment;
582
583                                                 // Calculate new font size
584                                                 int newFontSize = (int)Math.Round(this.Font.Size - this._autoFitFontSizeAdjustment);
585                                                 if(newFontSize < 1)
586                                                 {
587                                                         // Font can't be less than size 1
588                                                         newFontSize = 1;
589                                                 }
590
591                         // Create new font
592                         this.autofitFont = this.Common.ChartPicture.FontCache.GetFont(
593                                                         this.Font.FontFamily, 
594                                                         newFontSize, 
595                                                         this.Font.Style, 
596                                                         this.Font.Unit);
597
598                                                 // Calculate number of rows and columns 
599                                                 this.GetNumberOfRowsAndColumns(
600                                                         chartGraph, 
601                                                         this._legendItemsAreaPosition.Size,
602                                                         -1,
603                                                         out this._numberOfRowsPerColumn, 
604                                                         out this._itemColumns,
605                                                         out this._horizontalSpaceLeft,
606                                                         out this._verticalSpaceLeft);
607
608                                                 autoFitDone = (this._horizontalSpaceLeft >= 0 && this._verticalSpaceLeft >= 0);
609
610                                                 // Calculate total number of items fit and make sure we fit all of them
611                                                 itemsFit = 0;
612                                                 for(int index = 0; index < this._itemColumns; index++)
613                                                 {
614                                                         itemsFit += this._numberOfRowsPerColumn[index];
615                                                 }
616                                                 if(itemsFit < this._numberOfLegendItemsToProcess)
617                                                 {
618                                                         autoFitDone = false;
619                                                 }
620
621                                         }
622                                         else
623                                         {
624                                                 // If font size cannot be reduced start removing legend items
625                                                 if(this._numberOfLegendItemsToProcess > 2)
626                                                 {
627                                                         // Handle case of 1 column that do not fit horizontally
628                                                         if(this._itemColumns == 1 && (this._horizontalSpaceLeft < 0 && this._verticalSpaceLeft >= 0))
629                                                         {
630                                                                 autoFitDone = true;
631                                                                 this._numberOfLegendItemsToProcess = 
632                                                                         Math.Min(this._numberOfLegendItemsToProcess, this._numberOfRowsPerColumn[0]);
633                                                         }
634                                                         // Handle case of 1 row that do not fit vertically
635                                                         else if(this.GetMaximumNumberOfRows() == 1 && (this._verticalSpaceLeft < 0  && this._horizontalSpaceLeft >= 0))
636                                                         {
637                                                                 autoFitDone = true;
638                                                                 this._numberOfLegendItemsToProcess = 
639                                                                         Math.Min(this._numberOfLegendItemsToProcess, this._itemColumns);
640                                                         }
641                                                         else
642                                                         {
643                                                                 // Adjust legend items area height by size required to show
644                                                                 // visually (dots) that legend is truncated
645                                                                 if(!this._legendItemsTruncated)
646                                                                 {
647                                                                         this._legendItemsAreaPosition.Height -= this._truncatedDotsSize;
648                                                                 }
649
650                                                                 // Remove last legend item
651                                                                 this._legendItemsTruncated = true;
652                                                                 --this._numberOfLegendItemsToProcess;
653
654                                                                 // RecalculateAxesScale number of rows and columns
655                                                                 this.GetNumberOfRowsAndColumns(
656                                                                         chartGraph, 
657                                                                         this._legendItemsAreaPosition.Size,
658                                                                         this._numberOfLegendItemsToProcess,
659                                                                         out this._numberOfRowsPerColumn, 
660                                                                         out this._itemColumns);
661                                                         }
662
663                                                         // Make sure we show truncated legend symbols when not all items shown
664                                                         if(autoFitDone && 
665                                                                 !this._legendItemsTruncated &&
666                                                                 this._numberOfLegendItemsToProcess < this.legendItems.Count)
667                                                         {
668                                                                 // Adjust legend items area height by size required to show
669                                                                 // visually (dots) that legend is truncated
670                                                                 this._legendItemsAreaPosition.Height -= this._truncatedDotsSize;
671
672                                                                 // Legend is truncated
673                                                                 this._legendItemsTruncated = true;
674                                                         }
675                                                 }
676                                                 else
677                                                 {
678                                                         autoFitDone = true;
679                                                 }
680                                         
681                                                 // Check if legend items fit into the legend area
682                                                 if(!autoFitDone)
683                                                 {
684                                                         autoFitDone = this.CheckLegendItemsFit(
685                                                                 chartGraph,
686                                                                 this._legendItemsAreaPosition.Size,
687                                                                 this._numberOfLegendItemsToProcess,
688                                                                 this._autoFitFontSizeAdjustment,
689                                                                 this._itemColumns,
690                                                                 this._numberOfRowsPerColumn,
691                                                                 out this._subColumnSizes,
692                                                                 out this._cellHeights,
693                                                                 out this._horizontalSpaceLeft,
694                                                                 out this._verticalSpaceLeft);
695
696                                                 }
697                                         }
698                                 } while(!autoFitDone);
699                         }
700
701                 
702                         //***********************************************************
703                         //** Calculate position of all cells
704                         //***********************************************************
705
706                         // Calculate item vertical spacing in relative coordinates but rounded on pixel boundary
707                         Size itemHalfSpacing = Size.Empty;
708                         if(this._verticalSpaceLeft > 0)
709                         {
710                                 itemHalfSpacing.Height = (int)(this._verticalSpaceLeft / this.GetMaximumNumberOfRows() / 2);
711                         }
712                         if(this._horizontalSpaceLeft > 0)
713                         {
714                                 itemHalfSpacing.Width = (int)(_horizontalSpaceLeft / 2);
715                         }
716
717                         // Iterate through all legend items
718                         int currentColumn = 0;
719                         int currentRow = 0;
720                         if(this._numberOfLegendItemsToProcess < 0)
721                         {
722                                 this._numberOfLegendItemsToProcess = this.legendItems.Count;
723                         }
724                         for(int legendItemIndex = 0; legendItemIndex < this._numberOfLegendItemsToProcess; legendItemIndex++)
725                         {
726                                 LegendItem legendItem = this.legendItems[legendItemIndex];
727
728                                 // Iterate through legend item cells
729                                 for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
730                                 {
731                                         // Get legend cell
732                                         LegendCell legendCell = legendItem.Cells[cellIndex];
733
734                                         // Calculate cell position
735                                         Rectangle cellPosition = this.GetCellPosition(currentColumn, currentRow, cellIndex, itemHalfSpacing);
736
737                                         // Check if current cell spans through more than 1 cell
738                                         int overlappedCellsNumber = 0;
739                                         if(legendCell.CellSpan > 1)
740                                         {
741                                                 for(int spanIndex = 1; spanIndex < legendCell.CellSpan && (cellIndex + spanIndex) < legendItem.Cells.Count; spanIndex++)
742                                                 {
743                                                         // Calculate overlapped cell position
744                                                         Rectangle overlappedCellPosition = this.GetCellPosition(currentColumn, currentRow, cellIndex + spanIndex, itemHalfSpacing);
745
746                                                         // Adjust current cell right position
747                                                         if(cellPosition.Right < overlappedCellPosition.Right)
748                                                         {
749                                                                 cellPosition.Width += overlappedCellPosition.Right - cellPosition.Right;
750                                                         }
751
752                                                         // Increase number of overlapped cells
753                                                         ++overlappedCellsNumber;
754
755                                                         // Set empty size for the overlapped cells
756                                                         LegendCell overlappedLegendCell = legendItem.Cells[cellIndex + spanIndex];
757                                                         overlappedLegendCell.SetCellPosition( 
758                                                                 currentRow,
759                                                                 Rectangle.Empty, 
760                                                                 this.singleWCharacterSize);
761                                                 }
762                                         }
763
764                                         // Make sure cell is drawn inside the legend
765                                         cellPosition.Intersect(this._legendItemsAreaPosition);
766
767                                         // Set cell object position
768                                         legendCell.SetCellPosition(
769                                                 currentRow,
770                                                 cellPosition, 
771                                                 this.singleWCharacterSize);
772
773                                         // Skip overlapped cells
774                                         cellIndex += overlappedCellsNumber;
775                                 }
776
777                                 // Advance to the next row/column. Break if number of legend items exceed
778                                 // number of availabale rows/columns.
779                                 ++currentRow;
780                                 if(currentRow >= this._numberOfRowsPerColumn[currentColumn])
781                                 {
782                                         ++currentColumn;
783                                         currentRow = 0;
784                                         if(currentColumn >= this._itemColumns)
785                                         {
786                                                 break;
787                                         }
788                                 }
789                         }
790                 }
791
792                 /// <summary>
793                 /// Gets single cell position in relative coordinates.
794                 /// </summary>
795                 /// <param name="columnIndex">Cell column index.</param>
796                 /// <param name="rowIndex">Cell row index.</param>
797                 /// <param name="cellIndex">Index of the cell in the legend item.</param>
798                 /// <param name="itemHalfSpacing">Half legend item spacing in relative coordinates.</param>
799                 /// <returns></returns>
800                 private Rectangle GetCellPosition( 
801                         int columnIndex, 
802                         int rowIndex, 
803                         int cellIndex,
804                         Size itemHalfSpacing)
805                 {
806                         Rectangle cellPosition = this._legendItemsAreaPosition;
807
808                         //*****************************************************************
809                         //** Get cell Top location
810                         //*****************************************************************
811                         for(int index = 0; index < rowIndex; index++)
812                         {
813                                 cellPosition.Y += this._cellHeights[columnIndex, index];
814                         }
815                         if(itemHalfSpacing.Height > 0)
816                         {
817                                 cellPosition.Y += itemHalfSpacing.Height * rowIndex * 2 + itemHalfSpacing.Height;
818                         }
819
820                         //*****************************************************************
821                         //** Get cell Left location
822                         //*****************************************************************
823
824                         // Add extar space left after auto fitting
825                         if(this._horizontalSpaceLeft > 0)
826                         {
827                                 cellPosition.X += itemHalfSpacing.Width;
828                         }
829
830                         // Calculate how many sub-columns (cells) this legend has
831                         int numberOfSubColumns = this.GetNumberOfCells();
832
833                         // Iterate through all prev. columns
834                         for(int index = 0; index < columnIndex; index++)
835                         {
836                                 // Add width of previous columns
837                                 for(int subColumnIndex = 0; subColumnIndex < numberOfSubColumns; subColumnIndex++)
838                                 {
839                                         cellPosition.X += this._subColumnSizes[index, subColumnIndex];
840                                 }
841
842                                 // Add width of separator for the previous columns
843                                 cellPosition.X += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
844                         }
845                         // Add width of current column cells
846                         for(int subColumnIndex = 0; subColumnIndex < cellIndex; subColumnIndex++)
847                         {
848                                 cellPosition.X += this._subColumnSizes[columnIndex, subColumnIndex];
849                         }
850
851                         //*****************************************************************
852                         //** Get cell Height
853                         //*****************************************************************
854                         cellPosition.Height = this._cellHeights[columnIndex, rowIndex];
855                         
856                         //*****************************************************************
857                         //** Get cell Width
858                         //*****************************************************************
859                         cellPosition.Width = this._subColumnSizes[columnIndex, cellIndex];
860
861                         return cellPosition;
862                 }
863
864                 /// <summary>
865                 /// Calculates the optimal size of the legend.
866                 /// </summary>
867                 /// <param name="chartGraph">Chart graphics object.</param>
868                 /// <param name="maxSizeRel">Max size for the legend.</param>
869                 /// <returns>Legend optimal size.</returns>
870                 private SizeF GetOptimalSize(ChartGraphics chartGraph, SizeF maxSizeRel)
871                 {
872                         // Reset some values
873                         this._offset = Size.Empty;
874                         this._itemColumns = 0;
875                         this._horizontalSpaceLeft = 0;
876                         this._verticalSpaceLeft = 0;
877                         this._subColumnSizes = null;
878                         this._numberOfRowsPerColumn = null;
879                         this._cellHeights = null;
880                         this.autofitFont = null;
881                         this._autoFitFontSizeAdjustment = 0;
882                         this._numberOfCells = -1;
883                         this._numberOfLegendItemsToProcess = -1;
884                         Size    optimalSize = Size.Empty;
885
886                         // Convert to pixels
887                         SizeF maxSizeAbs = chartGraph.GetAbsoluteSize(maxSizeRel);
888                         Size maxSize = new Size((int)maxSizeAbs.Width, (int)maxSizeAbs.Height);
889
890                         // Clear all legend item cells cached information
891                         foreach(LegendItem legendItem in this.legendItems)
892                         {
893                                 foreach(LegendCell cell in legendItem.Cells)
894                                 {
895                                         cell.ResetCache();
896                                 }
897                         }
898
899                         // Check if legend is enabled
900                         if(this.IsEnabled())
901                         {
902                                 // Add all series legend into items collection and then add custom legend items
903                                 FillLegendItemsCollection();
904
905                                 // Call a notification event, so that legend items collection can be modified by user
906                 this.Common.Chart.CallOnCustomizeLegend(legendItems, this.Name);
907
908                                 // Check if there are any items in the legend
909                                 if(this.legendItems.Count > 0)
910                                 {
911                                         //***********************************************************
912                                         //** Use size of the "W" character in current font to 
913                                         //** calculate legend spacing
914                                         //***********************************************************
915                                         this.singleWCharacterSize =  chartGraph.MeasureStringAbs("W", this.Font);
916                                         Size doubleCharacterSize =  chartGraph.MeasureStringAbs("WW", this.Font);
917                                         this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
918                         
919                                         // Calculate left, top offset and column spacing
920                                         this._offset.Width = (int)Math.Ceiling(singleWCharacterSize.Width / 2f);
921                                         this._offset.Height = (int)Math.Ceiling(singleWCharacterSize.Width / 3f);
922                                         this._itemColumnSpacingRel = (int)(singleWCharacterSize.Width * (this._itemColumnSpacing / 100f));
923                                         if(this._itemColumnSpacingRel % 2 == 1)
924                                         {
925                                                 this._itemColumnSpacingRel += 1;
926                                         }
927
928
929                                         //***********************************************************
930                                         //** Add size required for the legend tile
931                                         //***********************************************************
932                                         
933                                         Size titleSize = Size.Empty;
934                                         if(this.Title.Length > 0)
935                                         {
936                                                 titleSize = this.GetTitleSize(chartGraph, maxSize);
937                                         }
938
939                                         //***********************************************************
940                                         //** Add size required for the legend header
941                                         //***********************************************************
942
943                                         Size highestHeader = Size.Empty;
944                                         foreach(LegendCellColumn legendColumn in this.CellColumns)
945                                         {
946                                                 if(legendColumn.HeaderText.Length > 0)
947                                                 {
948                                                         // Measure header text size
949                                                         Size headerSize = this.GetHeaderSize(chartGraph, legendColumn);
950
951                                                         // Get header with maximum height
952                                                         highestHeader.Height = Math.Max(highestHeader.Height, headerSize.Height);
953                                                 }
954                                         }
955
956                                         //***********************************************************
957                                         //** Calculate size available for legend items
958                                         //***********************************************************
959                                         Size legenItemsMaxSize = maxSize;
960                                         legenItemsMaxSize.Width -= 2 * (this._offset.Width + this.GetBorderSize());
961                                         legenItemsMaxSize.Height -= 2 * (this._offset.Height + this.GetBorderSize());
962                                         legenItemsMaxSize.Height -= titleSize.Height;
963                                         legenItemsMaxSize.Height -= highestHeader.Height;
964
965                                         //***********************************************************
966                                         //** Calculate number of rows and columns depending on
967                                         //** the legend style
968                                         //***********************************************************
969                     this._autoFitFontSizeAdjustment = 0;
970
971                                         this.autofitFont = this.Font;
972                                         int vertSpaceLeft = 0;
973                                         int horizSpaceLeft = 0;
974                                         bool reduceFont = this.IsTextAutoFit;
975                                         bool autoFit = false;
976                                         do
977                                         {
978                                                 // Get number of columns and rows that we can fit in the legend
979                                                 this.GetNumberOfRowsAndColumns(
980                                                         chartGraph, 
981                                                         legenItemsMaxSize,
982                                                         -1,
983                                                         out this._numberOfRowsPerColumn, 
984                                                         out this._itemColumns,
985                                                         out horizSpaceLeft,
986                                                         out vertSpaceLeft);
987
988                                                 // Calculate total number of items fit and make sure we fit all of them
989                                                 int itemsFit = 0;
990                                                 for(int index = 0; index < this._itemColumns; index++)
991                                                 {
992                                                         itemsFit += this._numberOfRowsPerColumn[index];
993                                                 }
994                                                 autoFit = (horizSpaceLeft >= 0 && vertSpaceLeft >= 0 && itemsFit >= this.legendItems.Count);
995
996                                                 // Check if items fit
997                                                 if(reduceFont && !autoFit)
998                                                 {
999                                                         if((this.Font.Size - this._autoFitFontSizeAdjustment) > this._autoFitMinFontSize)
1000                                                         {
1001                                                                 // Reduce font size by one 
1002                                                                 ++this._autoFitFontSizeAdjustment;
1003
1004                                                                 // Calculate new font size
1005                                                                 int newFontSize = (int)Math.Round(this.Font.Size - this._autoFitFontSizeAdjustment);
1006                                                                 if(newFontSize < 1)
1007                                                                 {
1008                                                                         // Font can't be less than size 1
1009                                                                         newFontSize = 1;
1010                                                                 }
1011
1012                                                                 // Create new font
1013                                 this.autofitFont = this.Common.ChartPicture.FontCache.GetFont(
1014                                                                         this.Font.FontFamily, 
1015                                                                         newFontSize, 
1016                                                                         this.Font.Style, 
1017                                                                         this.Font.Unit);
1018                                                         }
1019                                                         else
1020                                                         {
1021                                                                 reduceFont = false;
1022                                                         }
1023                                                 }
1024                                         } while(reduceFont && !autoFit);
1025
1026                                         // Slightly reduce used space 
1027                                         horizSpaceLeft -= Math.Min(4, horizSpaceLeft);
1028                                         vertSpaceLeft -= Math.Min(2, vertSpaceLeft);
1029
1030         
1031                                         //***********************************************************
1032                                         //** Calculate legend size
1033                                         //***********************************************************
1034                                         optimalSize.Width = (legenItemsMaxSize.Width - horizSpaceLeft);
1035                                         optimalSize.Width = Math.Max(optimalSize.Width, titleSize.Width);
1036                                         optimalSize.Width += 2 * (this._offset.Width + this.GetBorderSize());
1037
1038                                         optimalSize.Height = (legenItemsMaxSize.Height - vertSpaceLeft) + titleSize.Height + highestHeader.Height;
1039                                         optimalSize.Height += 2 * (this._offset.Height + this.GetBorderSize());
1040
1041                                         // Adjust legend items area height by size required to show
1042                                         // visually (dots) that legend is truncated
1043                                         if(horizSpaceLeft < 0 || vertSpaceLeft < 0)
1044                                         {
1045                                                 optimalSize.Height += this._truncatedDotsSize;
1046                                         }
1047
1048                                         //***********************************************************
1049                                         //** Make sure legend size do not exceed max. value
1050                                         //***********************************************************
1051                                         if(optimalSize.Width > maxSize.Width)
1052                                         {
1053                                                 optimalSize.Width = maxSize.Width;
1054                                         }
1055                                         if(optimalSize.Height > maxSize.Height)
1056                                         {
1057                                                 optimalSize.Height = maxSize.Height;
1058                                         }
1059                                         if(optimalSize.Width < 0)
1060                                         {
1061                                                 optimalSize.Width = 0;
1062                                         }
1063                                         if(optimalSize.Height < 0)
1064                                         {
1065                                                 optimalSize.Height = 0;
1066                                         }
1067                                 }
1068                         }
1069
1070                         // Convert result size from pixel to relative coordinates
1071                         return chartGraph.GetRelativeSize(optimalSize);
1072                 }
1073
1074
1075
1076                 /// <summary>
1077                 /// Recalculates legend position.
1078                 /// </summary>
1079                 /// <param name="chartGraph">Chart graphics used.</param>
1080                 /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
1081                 /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
1082                 internal void CalcLegendPosition(
1083                         ChartGraphics chartGraph, 
1084                         ref RectangleF chartAreasRectangle, 
1085                         float elementSpacing)
1086                 {
1087                         RectangleF      legendPosition = new RectangleF();
1088
1089                         // Get optimal legend size
1090                         SizeF maxSize = new SizeF(chartAreasRectangle.Width - 2*elementSpacing, chartAreasRectangle.Height - 2*elementSpacing);
1091             if (this.DockedToChartArea == Constants.NotSetValue)
1092                         {
1093
1094                 // Note: 'maxLegendSize' parameter is ignored. New legend property 
1095                 // 'maximumLegendAutoSize' is used instead.
1096                                 if(this.Docking == Docking.Top || this.Docking == Docking.Bottom)
1097                                 {
1098                     maxSize.Height = (maxSize.Height / 100F) * this._maximumLegendAutoSize;
1099                                 }
1100                                 else
1101                                 {
1102                     maxSize.Width = (maxSize.Width / 100F) * this._maximumLegendAutoSize;
1103                                 }
1104                         }
1105
1106                         if(maxSize.Width <= 0 || maxSize.Height <= 0)
1107                         {
1108                                 return;
1109                         }
1110                                 
1111                         SizeF legendSize = this.GetOptimalSize(chartGraph, maxSize);
1112                         legendPosition.Height = legendSize.Height;
1113                         legendPosition.Width = legendSize.Width;
1114                         if(float.IsNaN(legendSize.Height) || float.IsNaN(legendSize.Width))
1115                         {
1116                                 return;
1117                         }
1118
1119                         // Calculate legend position
1120                         if(this.Docking == Docking.Top)
1121                         {
1122                                 legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
1123                                 if(this.Alignment == StringAlignment.Near)
1124                                 {
1125                                         legendPosition.X = chartAreasRectangle.X + elementSpacing;
1126                                 }
1127                                 else if(this.Alignment == StringAlignment.Far)
1128                                 {
1129                                         legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
1130                                 }
1131                                 else if(this.Alignment == StringAlignment.Center)
1132                                 {
1133                                         legendPosition.X = chartAreasRectangle.X + (chartAreasRectangle.Width - legendSize.Width) / 2F;
1134                                 }
1135
1136                                 // Adjust position of the chart area(s)
1137                                 chartAreasRectangle.Height -= legendPosition.Height + elementSpacing;
1138                                 chartAreasRectangle.Y = legendPosition.Bottom;
1139                         }
1140                         else if(this.Docking == Docking.Bottom)
1141                         {
1142                                 legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
1143                                 if(this.Alignment == StringAlignment.Near)
1144                                 {
1145                                         legendPosition.X = chartAreasRectangle.X + elementSpacing;
1146                                 }
1147                                 else if(this.Alignment == StringAlignment.Far)
1148                                 {
1149                                         legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
1150                                 }
1151                                 else if(this.Alignment == StringAlignment.Center)
1152                                 {
1153                                         legendPosition.X = chartAreasRectangle.X + (chartAreasRectangle.Width - legendSize.Width) / 2F;
1154                                 }
1155
1156                                 // Adjust position of the chart area(s)
1157                                 chartAreasRectangle.Height -= legendPosition.Height + elementSpacing;
1158                         }
1159                         if(this.Docking == Docking.Left)
1160                         {
1161                                 legendPosition.X = chartAreasRectangle.X + elementSpacing;
1162                                 if(this.Alignment == StringAlignment.Near)
1163                                 {
1164                                         legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
1165                                 }
1166                                 else if(this.Alignment == StringAlignment.Far)
1167                                 {
1168                                         legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
1169                                 }
1170                                 else if(this.Alignment == StringAlignment.Center)
1171                                 {
1172                                         legendPosition.Y = chartAreasRectangle.Y + (chartAreasRectangle.Height - legendSize.Height) / 2F;
1173                                 }
1174
1175                                 // Adjust position of the chart area(s)
1176                                 chartAreasRectangle.Width -= legendPosition.Width + elementSpacing;
1177                                 chartAreasRectangle.X = legendPosition.Right;
1178                         }
1179                         if(this.Docking == Docking.Right)
1180                         {
1181                                 legendPosition.X = chartAreasRectangle.Right - legendSize.Width - elementSpacing;
1182                                 if(this.Alignment == StringAlignment.Near)
1183                                 {
1184                                         legendPosition.Y = chartAreasRectangle.Y + elementSpacing;
1185                                 }
1186                                 else if(this.Alignment == StringAlignment.Far)
1187                                 {
1188                                         legendPosition.Y = chartAreasRectangle.Bottom - legendSize.Height - elementSpacing;
1189                                 }
1190                                 else if(this.Alignment == StringAlignment.Center)
1191                                 {
1192                                         legendPosition.Y = chartAreasRectangle.Y + (chartAreasRectangle.Height - legendSize.Height) / 2F;
1193                                 }
1194
1195                                 // Adjust position of the chart area(s)
1196                                 chartAreasRectangle.Width -= legendPosition.Width + elementSpacing;
1197                         }
1198
1199                         this.Position.SetPositionNoAuto(legendPosition.X, legendPosition.Y, legendPosition.Width, legendPosition.Height);
1200                 }
1201
1202
1203
1204                 /// <summary>
1205                 /// Get number of columns and rows that can be fit in specified size.
1206                 /// </summary>
1207                 /// <param name="chartGraph">Chart graphics.</param>
1208                 /// <param name="legendSize">Legend size.</param>
1209                 /// <param name="numberOfItemsToCheck">Number of legend items to check.</param>
1210                 /// <param name="numberOfRowsPerColumn">Array with number of rows per each column.</param>
1211                 /// <param name="columnNumber">Returns number of columns.</param>
1212                 private void GetNumberOfRowsAndColumns(
1213                         ChartGraphics chartGraph, 
1214                         Size legendSize,
1215                         int numberOfItemsToCheck,
1216                         out int[] numberOfRowsPerColumn, 
1217                         out int columnNumber)
1218                 {
1219                         int horSpaceLeft = 0;
1220                         int vertSpaceLeft = 0;
1221                         this.GetNumberOfRowsAndColumns(
1222                                 chartGraph, 
1223                                 legendSize,
1224                                 numberOfItemsToCheck,
1225                                 out numberOfRowsPerColumn, 
1226                                 out columnNumber,
1227                                 out horSpaceLeft,
1228                                 out vertSpaceLeft);
1229                 }
1230
1231                 /// <summary>
1232                 /// Get number of columns and rows that can be fit in specified size.
1233                 /// </summary>
1234                 /// <param name="chartGraph">Chart graphics.</param>
1235                 /// <param name="legendSize">Legend size.</param>
1236                 /// <param name="numberOfItemsToCheck">Legend items number to check.</param>
1237                 /// <param name="numberOfRowsPerColumn">Array with number of rows per each column.</param>
1238                 /// <param name="columnNumber">Returns number of columns.</param>
1239                 /// <param name="horSpaceLeft">Returns horizontal spacing left.</param>
1240                 /// <param name="vertSpaceLeft">Returns vertical spacing left.</param>
1241                 private void GetNumberOfRowsAndColumns(
1242                         ChartGraphics chartGraph, 
1243                         Size legendSize,
1244                         int numberOfItemsToCheck,
1245                         out int[] numberOfRowsPerColumn, 
1246                         out int columnNumber,
1247                         out int horSpaceLeft,
1248                         out int vertSpaceLeft)
1249                 {
1250                         // Initialize output parameters
1251                         numberOfRowsPerColumn = null;
1252                         columnNumber = 1;
1253                         horSpaceLeft = 0;
1254                         vertSpaceLeft = 0;
1255
1256                         // If number of items to check is nor set use total number of items in the collection
1257                         if(numberOfItemsToCheck < 0)
1258                         {
1259                                 numberOfItemsToCheck = legendItems.Count;
1260                         }
1261
1262                         // Check legend style
1263                         if(this.LegendStyle == LegendStyle.Column || numberOfItemsToCheck <= 1)
1264                         {
1265                                 columnNumber = 1;
1266                                 numberOfRowsPerColumn = new int[] { numberOfItemsToCheck };
1267                         }
1268                         else if(this.LegendStyle == LegendStyle.Row)
1269                         {
1270                                 columnNumber = numberOfItemsToCheck;
1271                                 numberOfRowsPerColumn = new int[columnNumber];
1272                                 for(int index = 0; index < columnNumber; index++)
1273                                 {
1274                                         numberOfRowsPerColumn[index] = 1;
1275                                 }
1276                         }
1277                         else if(this.LegendStyle == LegendStyle.Table)
1278                         {
1279                                 // Start with 1 column and 1 row
1280                                 columnNumber = 1;
1281                                 numberOfRowsPerColumn = new int[] { 1 };
1282
1283                                 // Get legend table style and adjust number of columns and rows accordinly
1284                                 LegendTableStyle tableStyle = this.GetLegendTableStyle(chartGraph);
1285                                 
1286                                 //*********************************************************************************
1287                                 //** Tall table layout
1288                                 //*********************************************************************************
1289                                 if(tableStyle == LegendTableStyle.Tall)
1290                                 {
1291                                         // Iterate from second item trying to add them and check if their fit
1292                                         bool exitLoop = false;
1293                                         int legendItemIndex = 1;
1294                                         for(legendItemIndex = 1; !exitLoop && legendItemIndex < numberOfItemsToCheck; legendItemIndex ++)
1295                                         {
1296                                                 // Try to increase number of rows in the current column
1297                                                 ++numberOfRowsPerColumn[columnNumber - 1];
1298
1299                                                 // Check if legend items fit into the legend area
1300                                                 bool autoFitDone = this.CheckLegendItemsFit(
1301                                                         chartGraph,
1302                                                         legendSize,
1303                                                         legendItemIndex + 1,
1304                                                         this._autoFitFontSizeAdjustment,
1305                                                         columnNumber,
1306                                                         numberOfRowsPerColumn,
1307                                                         out this._subColumnSizes,
1308                                                         out this._cellHeights,
1309                                                         out horSpaceLeft,
1310                                                         out vertSpaceLeft);
1311
1312                                                 // Check if we fit or if we have just one column that do not fit
1313                                                 // horizontally but still have vertical space.
1314                                                 if(autoFitDone || 
1315                                                         ( (columnNumber == 1 || horSpaceLeft < 0) && vertSpaceLeft > 0) )
1316                                                 {
1317                                                         // Continue adding rows to the current column
1318                                                         continue;
1319                                                 }
1320                                                 else
1321                                                 {
1322                                                         // Reduce number of rows in the current column
1323                                                         if(numberOfRowsPerColumn[columnNumber - 1] > 1)
1324                                                         {
1325                                                                 --numberOfRowsPerColumn[columnNumber - 1];
1326                                                         }
1327
1328                                                         // Get half of average column width
1329                                                         int averageColumnWidth = 0;
1330                                                         if(horSpaceLeft > 0)
1331                                                         {
1332                                                                 averageColumnWidth = (int)Math.Round((double)(legendSize.Width - horSpaceLeft) / columnNumber) / 2;
1333                                                         }
1334
1335                                                          // Check if number of columns can be increased
1336                                                         if(columnNumber < 50 && horSpaceLeft >= averageColumnWidth)
1337                                                         {
1338                                                                 // Add new column
1339                                                                 ++columnNumber;
1340
1341                                                                 // Resize array that stores number of rows per column
1342                                                                 int[] tempArray = numberOfRowsPerColumn;
1343                                                                 numberOfRowsPerColumn = new int[columnNumber];
1344                                                                 for(int index = 0; index < tempArray.Length; index++)
1345                                                                 {
1346                                                                         numberOfRowsPerColumn[index] = tempArray[index];
1347                                                                 }
1348                                                                 numberOfRowsPerColumn[columnNumber - 1] = 1;
1349
1350                                                                 // If last legend item is moved into a new column
1351                                                                 // call the auto fitting method before leaving the loop
1352                                                                 if(legendItemIndex == numberOfItemsToCheck - 1)
1353                                                                 {
1354                                                                         this.CheckLegendItemsFit(
1355                                                                                 chartGraph,
1356                                                                                 legendSize,
1357                                                                                 legendItemIndex + 1,
1358                                                                                 this._autoFitFontSizeAdjustment,
1359                                                                                 columnNumber,
1360                                                                                 numberOfRowsPerColumn,
1361                                                                                 out this._subColumnSizes,
1362                                                                                 out this._cellHeights,
1363                                                                                 out horSpaceLeft,
1364                                                                                 out vertSpaceLeft);
1365                                                                 }
1366                                                         }
1367                                                         else
1368                                                         {
1369                                                                 exitLoop = true;
1370                                                         }
1371                                                 }
1372                                         }
1373
1374                                         // Check if we end up with legend with multiple columns
1375                                         // where last column has sinificantly lower height of all rows
1376                                         if(columnNumber > 1)
1377                                         {
1378                                                 // Try reducing number of rows in the "tall" calumns and move them 
1379                                                 // into the last column.
1380                                                 bool done = false;
1381                                                 while(!done)
1382                                                 {
1383                                                         // By default no more iterations required
1384                                                         done = true;
1385
1386                                                         // Find maximum column height not taking the last row in consideration
1387                                                         int maxColumnHeight = -1;
1388                                                         for(int columnIndex = 0; columnIndex < columnNumber; columnIndex++)
1389                                                         {
1390                                                                 // Calculate current column height not taking the last row in consideration
1391                                                                 int columnHeight = 0;
1392                                                                 for(int rowIndex = 0; rowIndex < this._numberOfRowsPerColumn[columnIndex] - 1; rowIndex++)
1393                                                                 {
1394                                                                         columnHeight += this._cellHeights[columnIndex, rowIndex];
1395                                                                 }
1396
1397                                                                 // Find maximum height
1398                                                                 maxColumnHeight = Math.Max(maxColumnHeight, columnHeight);
1399                                                         }
1400
1401                                                         // Calculate total height of items in the last row
1402                                                         int totalHieghtOfItemInLastRow = 0;
1403                                                         for(int columnIndex = 0; columnIndex < (columnNumber - 1); columnIndex++)
1404                                                         {
1405                                                                 if(this._numberOfRowsPerColumn[columnIndex] > 1)
1406                                                                 {
1407                                                                         totalHieghtOfItemInLastRow += this._cellHeights[columnIndex, this._numberOfRowsPerColumn[columnIndex] - 1];
1408                                                                 }
1409                                                         }
1410
1411                                                         // Check if rows are available for removal
1412                                                         if(totalHieghtOfItemInLastRow > 0)
1413                                                         {
1414                                                                 // Get last column height
1415                                                                 int lastColumnHeight = this.GetColumnHeight(columnNumber - 1);
1416
1417                                                                 // Check if all items in the last row can vertically fit in last column
1418                                                                 if( (lastColumnHeight + totalHieghtOfItemInLastRow) <= maxColumnHeight )
1419                                                                 {
1420                                                                         // Reduce number of rows in all columns except last
1421                                                                         int itemsToAdd = 0;
1422                                                                         for(int columnIndex = 0; columnIndex < (columnNumber - 1); columnIndex++)
1423                                                                         {
1424                                                                                 if(this._numberOfRowsPerColumn[columnIndex] > 1)
1425                                                                                 {
1426                                                                                         --this._numberOfRowsPerColumn[columnIndex];
1427                                                                                         ++itemsToAdd;
1428                                                                                 }
1429                                                                         }
1430
1431                                                                         // Add rows to last column
1432                                                                         if(itemsToAdd > 0)
1433                                                                         {
1434                                                                                 // Add roes into the last column
1435                                                                                 this._numberOfRowsPerColumn[columnNumber - 1] += itemsToAdd;
1436
1437                                                                                 // Check if legend items fit into the legend area
1438                                                                                 bool autoFitDone = this.CheckLegendItemsFit(
1439                                                                                         chartGraph,
1440                                                                                         legendSize,
1441                                                                                         legendItemIndex + 1,
1442                                                                                         this._autoFitFontSizeAdjustment,
1443                                                                                         columnNumber,
1444                                                                                         numberOfRowsPerColumn,
1445                                                                                         out this._subColumnSizes,
1446                                                                                         out this._cellHeights,
1447                                                                                         out horSpaceLeft,
1448                                                                                         out vertSpaceLeft);
1449
1450                                                                                 // Try doing one more time
1451                                                                                 done = false;
1452                                                                         }
1453                                                                 }
1454                                                         }
1455                                                 }
1456                                         }
1457                                 }
1458                                         //*********************************************************************************
1459                                         //** Wide table layout
1460                                         //*********************************************************************************
1461                                 else if(tableStyle == LegendTableStyle.Wide)
1462                                 {
1463                                         // Iterate from second item trying to add them and check if they fit
1464                                         bool exitLoop = false;
1465                                         int legendItemIndex = 1;
1466                                         for(legendItemIndex = 1; !exitLoop && legendItemIndex < numberOfItemsToCheck; legendItemIndex ++)
1467                                         {
1468                                                 // Try to increase number of columns
1469                                                 ++columnNumber;
1470
1471                                                 // Resize array that stores number of rows per column
1472                                                 int[] tempArray = numberOfRowsPerColumn;
1473                                                 numberOfRowsPerColumn = new int[columnNumber];
1474                                                 for(int index = 0; index < tempArray.Length; index++)
1475                                                 {
1476                                                         numberOfRowsPerColumn[index] = tempArray[index];
1477                                                 }
1478                                                 numberOfRowsPerColumn[columnNumber - 1] = 1;
1479
1480                                                 // Check if legend items fit into the legend area
1481                                                 bool autoFitDone = this.CheckLegendItemsFit(
1482                                                         chartGraph,
1483                                                         legendSize,
1484                                                         legendItemIndex + 1,
1485                                                         this._autoFitFontSizeAdjustment,
1486                                                         columnNumber,
1487                                                         numberOfRowsPerColumn,
1488                                                         out this._subColumnSizes,
1489                                                         out this._cellHeights,
1490                                                         out horSpaceLeft,
1491                                                         out vertSpaceLeft);
1492
1493                                                 // Check if we fit or if we have just one row that do not fit
1494                                                 // vertically but still have horizontal space.
1495                                                 if(autoFitDone || 
1496                                                         ( (this.GetMaximumNumberOfRows(numberOfRowsPerColumn) == 1 || vertSpaceLeft < 0) && horSpaceLeft > 0) )
1497                                                 {
1498                                                         // Continue adding columns
1499                                                         continue;
1500                                                 }
1501                                                 else
1502                                                 {
1503                                                         // Remove columns and increase number of rows
1504                                                         bool columnFitting = true;
1505                                                         while(columnFitting)
1506                                                         {
1507                                                                 columnFitting = false;
1508
1509                                                                 // If we can't fit current number of columns reduce current column number
1510                                                                 int rowsToAdd = 0;
1511                                                                 if(columnNumber > 1)
1512                                                                 {
1513                                                                         rowsToAdd = numberOfRowsPerColumn[columnNumber - 1];
1514                                                                         --columnNumber;
1515
1516                                                                         // Resize array that stores number of rows per column
1517                                                                         tempArray = numberOfRowsPerColumn;
1518                                                                         numberOfRowsPerColumn = new int[columnNumber];
1519                                                                         for(int index = 0; index < columnNumber; index++)
1520                                                                         {
1521                                                                                 numberOfRowsPerColumn[index] = tempArray[index];
1522                                                                         }
1523                                                                 }
1524
1525                                                                 // We may need to add more than 1 row
1526                                                                 for(int indexRowToAdd = 0; indexRowToAdd < rowsToAdd; indexRowToAdd++)
1527                                                                 {
1528                                                                         // Find first column with smallest height
1529                                                                         int smallestColumnIndex = -1;
1530                                                                         int columnMinHeight = int.MaxValue;
1531                                                                         for(int columnIndex = 0; columnIndex < columnNumber; columnIndex++)
1532                                                                         {
1533                                                                                 int columnHeight = this.GetColumnHeight(columnIndex);
1534                                                                                 int nextColumnFirstItemHeight = 0;
1535                                                                                 if(columnIndex < columnNumber - 1)
1536                                                                                 {
1537                                                                                         nextColumnFirstItemHeight = this._cellHeights[columnIndex + 1, 0];
1538                                                                                 }
1539                                                                                 if(columnHeight < columnMinHeight && 
1540                                                                                         (columnHeight + nextColumnFirstItemHeight) < legendSize.Height)
1541                                                                                 {
1542                                                                                         // Remember column index and height
1543                                                                                         columnMinHeight = columnHeight;
1544                                                                                         smallestColumnIndex = columnIndex;
1545                                                                                 }
1546                                                                         }
1547
1548                                                                         // No more items can fit
1549                                                                         if(smallestColumnIndex < 0)
1550                                                                         {
1551                                                                                 // Check if legend items fit into the legend area
1552                                                                                 autoFitDone = this.CheckLegendItemsFit(
1553                                                                                         chartGraph,
1554                                                                                         legendSize,
1555                                                                                         legendItemIndex + 1,
1556                                                                                         this._autoFitFontSizeAdjustment,
1557                                                                                         columnNumber,
1558                                                                                         numberOfRowsPerColumn,
1559                                                                                         out this._subColumnSizes,
1560                                                                                         out this._cellHeights,
1561                                                                                         out horSpaceLeft,
1562                                                                                         out vertSpaceLeft);
1563
1564                                                                                 exitLoop = true;
1565                                                                                 break;
1566                                                                         }
1567
1568                                                                         // Add new row to the smallest column
1569                                                                         ++numberOfRowsPerColumn[smallestColumnIndex];
1570
1571                                                                         // Check if next column will be removed if it contains only 1 row
1572                                                                         if(smallestColumnIndex < (columnNumber - 1))
1573                                                                         {
1574                                                                                 if(numberOfRowsPerColumn[smallestColumnIndex + 1] == 1)
1575                                                                                 {
1576                                                                                         // Shift number of rows per column
1577                                                                                         tempArray = numberOfRowsPerColumn;
1578                                                                                         for(int index = smallestColumnIndex + 1; index < tempArray.Length - 1; index++)
1579                                                                                         {
1580                                                                                                 numberOfRowsPerColumn[index] = tempArray[index + 1];
1581                                                                                         }
1582                                                                                         numberOfRowsPerColumn[columnNumber - 1] = 1;
1583                                                                                 }
1584                                                                         }
1585
1586                                                                         // Check if legend items fit into the legend area
1587                                                                         autoFitDone = this.CheckLegendItemsFit(
1588                                                                                 chartGraph,
1589                                                                                 legendSize,
1590                                                                                 legendItemIndex + 1,
1591                                                                                 this._autoFitFontSizeAdjustment,
1592                                                                                 columnNumber,
1593                                                                                 numberOfRowsPerColumn,
1594                                                                                 out this._subColumnSizes,
1595                                                                                 out this._cellHeights,
1596                                                                                 out horSpaceLeft,
1597                                                                                 out vertSpaceLeft);
1598
1599                                                                 }
1600
1601                                                                 // If there is more than 1 column and items do not fit
1602                                                                 // horizontally - reduce number of columns.
1603                                                                 if(!autoFitDone && 
1604                                                                         horSpaceLeft < 0f && 
1605                                                                         columnNumber > 1)
1606                                                                 {
1607                                                                         columnFitting = true;
1608                                                                 }
1609                                                         }
1610                                                 }
1611                                         }
1612                                 }
1613                         }
1614
1615                         // Check if items fit and how much empty space left
1616                         this.CheckLegendItemsFit(
1617                                 chartGraph,
1618                                 legendSize,
1619                                 -1,
1620                                 this._autoFitFontSizeAdjustment,
1621                                 columnNumber,
1622                                 numberOfRowsPerColumn,
1623                                 out this._subColumnSizes,
1624                                 out this._cellHeights,
1625                                 out horSpaceLeft,
1626                                 out vertSpaceLeft);
1627                 }
1628                 
1629         /// <summary>
1630                 /// Gets column height.
1631                 /// </summary>
1632                 /// <param name="columnIndex">Index of the column to get the height for.</param>
1633                 /// <returns>Column height in relative coordinates.</returns>
1634                 private int GetColumnHeight(int columnIndex)
1635                 {
1636                         // Calculate current column height
1637                         int columnHeight = 0;
1638                         for(int rowIndex = 0; rowIndex < this._numberOfRowsPerColumn[columnIndex]; rowIndex++)
1639                         {
1640                                 columnHeight += this._cellHeights[columnIndex, rowIndex];
1641                         }
1642
1643                         return columnHeight;
1644                 }
1645
1646         /// <summary>
1647         /// Checks if legend background is selected.
1648         /// </summary>
1649         internal void SelectLegendBackground()
1650         {
1651             Common.HotRegionsList.AddHotRegion(this.Position.ToRectangleF(), this, ChartElementType.LegendArea, true);
1652         }
1653
1654                 #endregion Legend position & size methods
1655
1656                 #region Legend Items Fitting Methods
1657
1658                 /// <summary>
1659                 /// Gets maximum number of rows in all columns.
1660                 /// </summary>
1661                 /// <returns>Maximum number of rows.</returns>
1662                 private int GetMaximumNumberOfRows()
1663                 {
1664                         return this.GetMaximumNumberOfRows(this._numberOfRowsPerColumn);
1665                 }
1666
1667                 /// <summary>
1668                 /// Gets maximum number of rows in all columns.
1669                 /// </summary>
1670                 /// <param name="rowsPerColumn">Array that stores number of rows per column.</param>
1671                 /// <returns>Maximum number of rows.</returns>
1672                 private int GetMaximumNumberOfRows(int[] rowsPerColumn)
1673                 {
1674                         // Find column with maximum number of rows
1675                         int maxNumberOfColumns = 0;
1676                         if(rowsPerColumn != null)
1677                         {
1678                                 for(int columnIndex = 0; columnIndex < rowsPerColumn.Length; columnIndex++)
1679                                 {
1680                                         maxNumberOfColumns = Math.Max(maxNumberOfColumns, rowsPerColumn[columnIndex]);
1681                                 }
1682                         }
1683                         return maxNumberOfColumns;
1684                 }
1685
1686                 /// <summary>
1687                 /// Checks if specified legend will fit the specified size.
1688                 /// </summary>
1689                 /// <param name="graph">Chart graphics.</param>
1690                 /// <param name="legendItemsAreaSize">Area that legend items must fit.</param>
1691                 /// <param name="numberOfItemsToCheck">Number of items that should be fitted.</param>
1692                 /// <param name="fontSizeReducedBy">Number of points the standard legend font is reduced by auto-fitting algorithm.</param>
1693                 /// <param name="numberOfColumns">Legend column number.</param>
1694                 /// <param name="numberOfRowsPerColumn">Array of number of rows per column.</param>
1695                 /// <param name="subColumnSizes">Returns array of sub-column size.</param>
1696                 /// <param name="cellHeights">Returns array of cell heights.</param>
1697                 /// <param name="horizontalSpaceLeft">Returns horizontal space left.</param>
1698                 /// <param name="verticalSpaceLeft">Returns vertical space left.</param>
1699                 /// <returns>True if items fit.</returns>
1700                 private bool CheckLegendItemsFit(
1701                         ChartGraphics graph, 
1702                         Size legendItemsAreaSize,
1703                         int numberOfItemsToCheck,
1704                         int fontSizeReducedBy,
1705                         int numberOfColumns,
1706                         int[] numberOfRowsPerColumn,
1707                         out int[,] subColumnSizes,
1708                         out int[,] cellHeights,
1709                         out int horizontalSpaceLeft,
1710                         out int verticalSpaceLeft)
1711                 {
1712                         bool fitFlag = true;
1713
1714                         // Initialize output values
1715                         horizontalSpaceLeft = 0;
1716                         verticalSpaceLeft = 0;
1717
1718                         // Use current legend item count if number of items to check is not specified
1719                         if(numberOfItemsToCheck < 0)
1720                         {
1721                                 numberOfItemsToCheck = this.legendItems.Count;
1722                         }
1723
1724                         // Calculate how many sub-columns (cells) this legend has
1725                         int numberOfSubColumns = this.GetNumberOfCells();
1726
1727                         // Each column may have its own number of rows. Calculate the maximum number of rows.
1728                         int maxNumberOfRows = this.GetMaximumNumberOfRows(numberOfRowsPerColumn);
1729
1730                         // Create multidimensional arrays that will be holding the widths and heightsof all 
1731                         // individual cells. First dimension will be the legend column index, second dimension 
1732                         // is row index and the third is sub-column (cell) index.
1733                         int[,,] cellWidths = new int[numberOfColumns, maxNumberOfRows, numberOfSubColumns];
1734                         cellHeights = new int[numberOfColumns, maxNumberOfRows];
1735
1736
1737                         //*************************************************************************
1738                         //** Measure legend font single character
1739                         //*************************************************************************
1740                         this.singleWCharacterSize =  graph.MeasureStringAbs("W", (this.autofitFont == null) ? this.Font : this.autofitFont);
1741                         Size doubleCharacterSize =  graph.MeasureStringAbs("WW", (this.autofitFont == null) ? this.Font : this.autofitFont);
1742                         this.singleWCharacterSize.Width = doubleCharacterSize.Width - this.singleWCharacterSize.Width;
1743
1744
1745                         //*************************************************************************
1746                         //** Iterate through all legend items and measure each individual cell
1747                         //*************************************************************************
1748                         int currentColumn = 0;
1749                         int currentRow = 0;
1750                         for(int legendItemIndex = 0; legendItemIndex < numberOfItemsToCheck; legendItemIndex++)
1751                         {
1752                                 LegendItem legendItem = this.legendItems[legendItemIndex];
1753
1754                                 // Iterate through legend item cells
1755                                 int numberOfCellsToSkip = 0;
1756                                 for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
1757                                 {
1758                                         // Get legend cell
1759                                         LegendCell legendCell = legendItem.Cells[cellIndex];
1760
1761                                         // Get assocated legend column object (may be NULL)
1762                                         LegendCellColumn legendColumn = null;
1763                                         if(cellIndex < this.CellColumns.Count)
1764                                         {
1765                                                 legendColumn = this.CellColumns[cellIndex];
1766                                         }
1767
1768                                         // Check if current cell should be skipped becuse it's overlapped 
1769                                         // by the previous sell that uses CellSpan.
1770                                         if(numberOfCellsToSkip > 0)
1771                                         {
1772                                                 // Put size (-1) for the cells that follow a cell using ColumnSpan
1773                                                 cellWidths[currentColumn, currentRow, cellIndex] = -1;
1774                                                 --numberOfCellsToSkip;
1775                                                 continue;
1776                                         }
1777
1778                                         // Check if current cell uses CellSpan
1779                                         if(legendCell.CellSpan > 1)
1780                                         {
1781                                                 numberOfCellsToSkip = legendCell.CellSpan - 1;
1782                                         }
1783
1784                                         // Measure cell and store the value in the array
1785                                         Size cellSize = legendCell.MeasureCell(
1786                                                 graph, 
1787                                                 fontSizeReducedBy,
1788                                                 (this.autofitFont == null) ? this.Font : this.autofitFont,
1789                                                 this.singleWCharacterSize);
1790
1791                                         // Check for column maximum/minimum cell width restrictions
1792                                         if(legendColumn != null)
1793                                         {
1794                                                 if(legendColumn.MinimumWidth >= 0)
1795                                                 {
1796                                                         cellSize.Width = (int)Math.Max(cellSize.Width, legendColumn.MinimumWidth * singleWCharacterSize.Width / 100f);
1797                                                 }
1798                                                 if(legendColumn.MaximumWidth >= 0)
1799                                                 {
1800                                                         cellSize.Width = (int)Math.Min(cellSize.Width, legendColumn.MaximumWidth * singleWCharacterSize.Width / 100f);
1801                                                 }
1802                                         }
1803
1804                                         // Store cell size in arrays
1805                                         cellWidths[currentColumn, currentRow, cellIndex] = cellSize.Width;
1806                                         if(cellIndex == 0)
1807                                         {
1808                                                 cellHeights[currentColumn, currentRow] = cellSize.Height;
1809                                         }
1810                                         else
1811                                         {
1812                                                 cellHeights[currentColumn, currentRow] = 
1813                                                         Math.Max(cellHeights[currentColumn, currentRow], cellSize.Height);
1814                                         }
1815                                 }
1816
1817                                 // Advance to the next row/column. Break if number of legend items exceed
1818                                 // number of availabale rows/columns.
1819                                 ++currentRow;
1820                                 if(currentRow >= numberOfRowsPerColumn[currentColumn])
1821                                 {
1822                                         ++currentColumn;
1823                                         currentRow = 0;
1824                                         if(currentColumn >= numberOfColumns)
1825                                         {
1826                                                 // Check if we were able to fit all the items
1827                                                 if(legendItemIndex < numberOfItemsToCheck - 1)
1828                                                 {
1829                                                         fitFlag = false;
1830                                                 }
1831                                                 break;
1832                                         }
1833                                 }
1834                         }
1835
1836                         //*************************************************************************
1837                         //** For each sub-column get the maximum cell width
1838                         //*************************************************************************
1839                         subColumnSizes = new int[numberOfColumns, numberOfSubColumns];
1840                         bool secondIterationRequired = false;
1841                         for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
1842                         {
1843                                 for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
1844                                 {
1845                                         int width = 0;
1846                                         for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
1847                                         {
1848                                                 // Get current cell size
1849                                                 int cellWidth = cellWidths[currentColumn, currentRow, currentSubColumn];
1850
1851                                                 // Skip overlapped cells and cells that use ColumnSpan during the 
1852                                                 // first iteration. Their size will be determined during the 
1853                                                 // second iteration.
1854                                                 if(cellWidth < 0)
1855                                                 {
1856                                                         secondIterationRequired = true;
1857                                                         continue;
1858                                                 }
1859                                                 if(currentSubColumn + 1 < numberOfSubColumns)
1860                                                 {
1861                                                         int nextCellWidth = cellWidths[currentColumn, currentRow, currentSubColumn + 1];
1862                                                         if(nextCellWidth < 0)
1863                                                         {
1864                                                                 continue;
1865                                                         }
1866                                                 }
1867
1868                                                 // Get maximum width
1869                                                 width = Math.Max(width, cellWidth );
1870                                         }
1871
1872                                         // Store maximum width in the array
1873                                         subColumnSizes[currentColumn, currentSubColumn] = width;
1874                                 }
1875                         }
1876
1877                         //*************************************************************************
1878                         //** If leagend header text is used check if it fits into the currenly
1879                         //** calculated sub-column sizes.
1880                         //*************************************************************************
1881
1882                         for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
1883                         {
1884                                 for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
1885                                 {
1886                                         if(currentSubColumn < this.CellColumns.Count)
1887                                         {
1888                                                 LegendCellColumn legendColumn = this.CellColumns[currentSubColumn];
1889                                                 if(legendColumn.HeaderText.Length > 0)
1890                                                 {
1891                                                         // Note that extra "I" character added to add more horizontal spacing
1892                                                         Size headerTextSize =  graph.MeasureStringAbs(legendColumn.HeaderText + "I", legendColumn.HeaderFont);
1893                                                         if(headerTextSize.Width > subColumnSizes[currentColumn, currentSubColumn])
1894                                                         {
1895                                                                 // Set new width
1896                                                                 subColumnSizes[currentColumn, currentSubColumn] = headerTextSize.Width;
1897
1898                                                                 // Check for column maximum/minimum cell width restrictions
1899                                                                 if(legendColumn.MinimumWidth >= 0)
1900                                                                 {
1901                                                                         subColumnSizes[currentColumn, currentSubColumn] = 
1902                                                                                 (int)Math.Max(subColumnSizes[currentColumn, currentSubColumn], legendColumn.MinimumWidth * singleWCharacterSize.Width / 100f);
1903                                                                 }
1904                                                                 if(legendColumn.MaximumWidth >= 0)
1905                                                                 {
1906                                                                         subColumnSizes[currentColumn, currentSubColumn] = 
1907                                                                                 (int)Math.Min(subColumnSizes[currentColumn, currentSubColumn], legendColumn.MaximumWidth * singleWCharacterSize.Width / 100f);
1908                                                                 }
1909                                                         }
1910                                                 }
1911                                         }
1912                                 }
1913                         }
1914
1915                         //*************************************************************************
1916                         //** Adjust width of the cells to fit cell content displayed across 
1917                         //** several cells (CellSpanning).
1918                         //*************************************************************************
1919                         if(secondIterationRequired)
1920                         {
1921                                 for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)
1922                                 {
1923                                         for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
1924                                         {
1925                                                 for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
1926                                                 {
1927                                                         // Get current cell size
1928                                                         int cellWidth = cellWidths[currentColumn, currentRow, currentSubColumn];
1929
1930                                                         // Second iteration used to adjust width of the cells that are used to
1931                                                         // draw content across several horizontal cells (CellSpanning)
1932                                                         // Check if current cell will be spanned to the next ones
1933                                                         int cellSpan = 0;
1934                                                         while(currentSubColumn + cellSpan + 1 < numberOfSubColumns)
1935                                                         {
1936                                                                 int nextCellWidth = cellWidths[currentColumn, currentRow, currentSubColumn + cellSpan + 1];
1937                                                                 if(nextCellWidth >= 0)
1938                                                                 {
1939                                                                         break;  
1940                                                                 }
1941                                                                 ++cellSpan;
1942                                                         }
1943                                                         
1944
1945                                                         // Cell span was detected
1946                                                         if(cellSpan > 0)
1947                                                         {
1948                                                                 // Calculate total width of current cell and all overlapped cells
1949                                                                 int spanWidth = 0;
1950                                                                 for(int index = 0; index <= cellSpan; index++)
1951                                                                 {
1952                                                                         spanWidth += subColumnSizes[currentColumn, currentSubColumn + index];
1953                                                                 }
1954
1955                                                                 // Check if current cell fits into the cell span
1956                                                                 if(cellWidth > spanWidth)
1957                                                                 {
1958                                                                         // Adjust last span cell width to fit all curent cell content
1959                                                                         subColumnSizes[currentColumn, currentSubColumn + cellSpan] += cellWidth - spanWidth;
1960                                                                 }
1961                                                         }
1962                                                 }
1963                                         }
1964                                 }
1965                         }
1966                 
1967
1968                         //*************************************************************************
1969                         //** Check if equally spaced legend columns are used
1970                         //*************************************************************************
1971                         if(this.IsEquallySpacedItems)
1972                         {
1973                                 // Makre sure that same sub-colimn width are used in all columns
1974                                 for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
1975                                 {
1976                                         int width = 0;
1977                                         for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)        
1978                                         {
1979                                                 width = Math.Max(width, subColumnSizes[currentColumn, currentSubColumn]);
1980                                         }
1981
1982                                         // Set new sub-column width for each column
1983                                         for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)        
1984                                         {
1985                                                 subColumnSizes[currentColumn, currentSubColumn] = width;
1986                                         }
1987                                 }
1988                         }
1989
1990                         //*************************************************************************
1991                         //** Calculate total width and height occupied by all cells
1992                         //*************************************************************************
1993                         int totalWidth = 0;
1994                         int totalTableColumnSpacingWidth = 0;
1995                         for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)        
1996                         {
1997                                 // Add up all sub-columns
1998                                 for(int currentSubColumn = 0; currentSubColumn < numberOfSubColumns; currentSubColumn++)
1999                                 {
2000                                         totalWidth += subColumnSizes[currentColumn, currentSubColumn];
2001                                 }
2002
2003                                 // Add spacer between columns
2004                                 if(currentColumn < numberOfColumns - 1)
2005                                 {
2006                                         totalTableColumnSpacingWidth += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
2007                                 }
2008                         }
2009
2010                         int totalHeight = 0;
2011                         for(currentColumn = 0; currentColumn < numberOfColumns; currentColumn++)        
2012                         {
2013                                 int columnHeight = 0;
2014                                 for(currentRow = 0; currentRow < numberOfRowsPerColumn[currentColumn]; currentRow++)
2015                                 {
2016                                         columnHeight += cellHeights[currentColumn, currentRow];
2017                                 }
2018
2019                                 totalHeight = Math.Max(totalHeight, columnHeight);
2020                         }
2021
2022                         //*************************************************************************
2023                         //** Check if everything fits
2024                         //*************************************************************************
2025                         horizontalSpaceLeft = legendItemsAreaSize.Width - totalWidth - totalTableColumnSpacingWidth;
2026                         if(horizontalSpaceLeft < 0)
2027                         {
2028                                 fitFlag = false;
2029                         }
2030                         
2031                         verticalSpaceLeft = legendItemsAreaSize.Height - totalHeight;
2032                         if(verticalSpaceLeft < 0)
2033                         {
2034                                 fitFlag = false;
2035                         }
2036
2037                         return fitFlag;
2038                 }
2039
2040                 /// <summary>
2041                 /// Gets maximum number of legend cells defined as Column objects
2042                 /// or Cells in the custom legend items.
2043                 /// </summary>
2044                 /// <returns>Maximum number of cells.</returns>
2045                 private int GetNumberOfCells()
2046                 {
2047                         // Calculate cell number if it was not previously cached
2048                         if(this._numberOfCells < 0)
2049                         {
2050                                 // Initialize with number of defined columns
2051                                 this._numberOfCells = this.CellColumns.Count;
2052
2053                                 // Check if number of cells in legend items exceed number of defined columns
2054                                 foreach(LegendItem legendItem in this.legendItems)
2055                                 {
2056                                         this._numberOfCells = Math.Max(this._numberOfCells, legendItem.Cells.Count);
2057                                 }
2058                         }               
2059                         return this._numberOfCells;
2060                 }
2061
2062                 #endregion // Legend Items Fitting Methods
2063
2064                 #region Legend items collection filling methods
2065
2066                 /// <summary>
2067                 /// Add all series legend into items collection and then
2068                 /// add custom legend items.
2069                 /// </summary>
2070                 private void FillLegendItemsCollection()
2071                 {
2072                         // Clear all items
2073                         legendItems.Clear();
2074
2075                         // Check that there is no invalid legend names in the series
2076                         foreach(Series series in this.Common.DataManager.Series)
2077                         {
2078                 if (this.Common.ChartPicture.Legends.IndexOf(series.Legend)<0)
2079                 {
2080                     throw (new InvalidOperationException(SR.ExceptionLegendReferencedInSeriesNotFound(series.Name, series.Legend)));
2081                 }
2082                         }
2083
2084                         // Flag which indicates that series requires legend items to be reversed
2085                         bool    seriesWithReversedLegendItemsPresent = false;
2086
2087                         // Add legend items based on the exsisting chart series
2088                         foreach(Series series in this.Common.DataManager.Series)
2089                         {
2090                 // Check if series uses this legend
2091                 // VSTS issue #140694 fix: support of series.Legend = "Default";
2092                 if (this.Common.ChartPicture.Legends[series.Legend] != this)
2093                                 {
2094                                         continue;
2095                                 }
2096
2097                                 // Make sure series is assigned to the chart area
2098                                 if(series.ChartArea.Length > 0)
2099                                 {
2100                                         // Check if chart area name is valid
2101                                         bool areaNameFound = false;
2102                                         foreach(ChartArea area in this.Common.ChartPicture.ChartAreas)
2103                                         {
2104                                                 if(area.Name == series.ChartArea)
2105                                                 {
2106                                                         areaNameFound = true;
2107                                                         break;
2108                                                 }
2109                                         }
2110
2111                                         // Check if series is visible and valid chart area name was used
2112                                         if(series.IsVisible() && areaNameFound)
2113                                         {
2114                                                 // Check if we should add all data points into the legend
2115                                                 IChartType chartType = this.Common.ChartTypeRegistry.GetChartType(series.ChartTypeName);
2116
2117
2118                                                 // Check if series legend items should be reversed
2119                         if (this.LegendItemOrder == LegendItemOrder.Auto)
2120                                                 {
2121                                                         if(series.ChartType == SeriesChartType.StackedArea || 
2122                                                                 series.ChartType == SeriesChartType.StackedArea100 || 
2123                                                                 series.ChartType == SeriesChartType.Pyramid || 
2124                                                                 series.ChartType == SeriesChartType.StackedColumn || 
2125                                                                 series.ChartType == SeriesChartType.StackedColumn100 )
2126                                                         {
2127                                                                 seriesWithReversedLegendItemsPresent = true;
2128                                                         }
2129                                                 }
2130                                                 // Add item(s) based on series points label and fore color
2131                                                 if(chartType.DataPointsInLegend)
2132                                                 {
2133                                                         // Check if data points have X values set
2134                                                         bool    xValuesSet = false;
2135                                                         foreach(DataPoint point in series.Points)
2136                                                         {
2137                                                                 if(point.XValue != 0.0)
2138                                                                 {
2139                                                                         xValuesSet = true;
2140                                                                         break;
2141                                                                 }
2142                                                         }
2143
2144                                                         // Add legend items for each point
2145                                                         int index = 0;
2146                                                         foreach(DataPoint point in series.Points)
2147                                                         {
2148                                                                 // Do not show empty data points in the legend
2149                                                                 if(point.IsEmpty)
2150                                                                 {
2151                                                                         ++index;
2152                                                                         continue;
2153                                                                 }
2154
2155                                                                 // Point should not be shown in the legend
2156                                                                 if(!point.IsVisibleInLegend)
2157                                                                 {
2158                                                                         ++index;
2159                                                                         continue;
2160                                                                 }
2161
2162                                                                 // Create new legend item
2163                                                                 LegendItem      item = new LegendItem(point.Label, point.Color, "");
2164
2165                                                                 // Check if series is drawn in 3D chart area
2166                                                                 bool area3D = this.Common.Chart.ChartAreas[series.ChartArea].Area3DStyle.Enable3D;
2167
2168                                                                 // Set legend item appearance properties
2169                                                                 item.SetAttributes(this.Common, series);
2170                                                                 item.SetAttributes(point, area3D);
2171
2172                                                                 // Set chart image map properties
2173                                                                 item.ToolTip = point.ReplaceKeywords(point.LegendToolTip);
2174 #if !Microsoft_CONTROL
2175                                                                 item.MapAreaAttributes = point.ReplaceKeywords(point.LegendMapAreaAttributes);
2176                                 item.PostBackValue = point.ReplaceKeywords(point.LegendPostBackValue);
2177                                                                 item.Url = point.ReplaceKeywords(point.LegendUrl);
2178 #endif
2179                                                                 item.Name = point.ReplaceKeywords(point.LegendText);
2180
2181                                                                 item.SeriesPointIndex = index++;
2182                                                                 if(item.Name.Length == 0)
2183                                                                 {
2184                                                                         item.Name = point.ReplaceKeywords((point.Label.Length > 0) ? point.Label : point.AxisLabel);
2185                                                                 }
2186
2187                                                                 // If legend item name is not defined - try using the X value
2188                                                                 if(item.Name.Length == 0 && xValuesSet)
2189                                                                 {
2190                                                                         item.Name = ValueConverter.FormatValue(
2191                                                                                 series.Chart,
2192                                                                                 this,
2193                                         this.Tag,
2194                                                                                 point.XValue, 
2195                                                                                 "", // Do not use point label format! For Y values only! point.LabelFormat, 
2196                                                                                 point.series.XValueType,
2197                                                                                 ChartElementType.LegendItem);
2198                                                                 }
2199
2200                                                                 // If legend item name is not defined - use index
2201                                                                 if(item.Name.Length == 0)
2202                                                                 {
2203                                                                         item.Name = "Point " + index;
2204                                                                 }
2205
2206                                                                 // Add legend item cells based on predefined columns
2207                                                                 item.AddAutomaticCells(this);
2208                                                                 foreach(LegendCell cell in item.Cells)
2209                                                                 {
2210                                                                         if(cell.Text.Length > 0)
2211                                                                         {
2212                                                                                 // #LEGENDTEXT - series name
2213                                                                                 cell.Text = cell.Text.Replace(KeywordName.LegendText, item.Name);
2214
2215                                                                                 // Process rest of the keywords
2216                                                                                 cell.Text = point.ReplaceKeywords(cell.Text);
2217                                                                                 cell.ToolTip = point.ReplaceKeywords(cell.ToolTip);
2218 #if !Microsoft_CONTROL
2219                                                                                 cell.Url = point.ReplaceKeywords(cell.Url);
2220                                                                                 cell.MapAreaAttributes = point.ReplaceKeywords(cell.MapAreaAttributes);
2221                                         cell.PostBackValue = point.ReplaceKeywords(cell.PostBackValue);
2222 #endif // !Microsoft_CONTROL
2223                                                                         }
2224                                                                 }
2225
2226                                                                 legendItems.Add(item);
2227                                                         }
2228                                                 }
2229
2230                                                         // Add item based on series name and fore color
2231                                                 else
2232                                                 {
2233                                                         // Point should not be shown in the legend
2234                                                         if(!series.IsVisibleInLegend)
2235                                                         {
2236                                                                 continue;
2237                                                         }
2238
2239                                                         // Create legend item
2240                                                         LegendItem      item = new LegendItem(series.Name, series.Color, "");
2241                                                         item.SetAttributes(this.Common, series);
2242
2243                                                         item.ToolTip = series.ReplaceKeywords(series.LegendToolTip);
2244 #if !Microsoft_CONTROL
2245                                                         item.Url = series.ReplaceKeywords(series.LegendUrl);
2246                                                         item.MapAreaAttributes = series.ReplaceKeywords(series.LegendMapAreaAttributes);
2247                             item.PostBackValue = series.ReplaceKeywords(series.LegendPostBackValue);
2248 #endif // !Microsoft_CONTROL
2249
2250                             if (series.LegendText.Length > 0)
2251                                                         {
2252                                                                 item.Name = series.ReplaceKeywords(series.LegendText);
2253                                                         }
2254
2255                                                         // Add legend item cells based on predefined columns
2256                                                         item.AddAutomaticCells(this);
2257                                                         foreach(LegendCell cell in item.Cells)
2258                                                         {
2259                                                                 if(cell.Text.Length > 0)
2260                                                                 {
2261                                                                         // #LEGENDTEXT - series name
2262                                                                         cell.Text = cell.Text.Replace(KeywordName.LegendText, item.Name);
2263
2264                                                                         // Process rest of the keywords
2265                                                                         cell.Text = series.ReplaceKeywords(cell.Text);
2266                                                                         cell.ToolTip = series.ReplaceKeywords(cell.ToolTip);
2267 #if !Microsoft_CONTROL
2268                                                                         cell.Url = series.ReplaceKeywords(cell.Url);
2269                                                                         cell.MapAreaAttributes = series.ReplaceKeywords(cell.MapAreaAttributes);
2270                                     cell.PostBackValue = series.ReplaceKeywords(cell.PostBackValue);
2271 #endif // !Microsoft_CONTROL
2272                                                                 }
2273                                                         }
2274
2275                             legendItems.Add(item);
2276                                                 }
2277                                         }
2278                                 }
2279                         }
2280                 
2281
2282                         // Check if series legend items should be reversed
2283             if (this.LegendItemOrder == LegendItemOrder.SameAsSeriesOrder ||
2284                 (this.LegendItemOrder == LegendItemOrder.Auto && seriesWithReversedLegendItemsPresent))
2285                         {
2286                                 // Reversed series generated legend items
2287                                 legendItems.Reverse();
2288                         }
2289
2290
2291                         // Add custom items
2292                         foreach(LegendItem item in this._customLegends)
2293                         {
2294                                 if(item.Enabled)
2295                                 {
2296                                         legendItems.Add(item);
2297                                 }
2298                         }
2299
2300                         // Legend can't be empty at design time
2301                         if(legendItems.Count == 0 && this.Common != null && this.Common.Chart != null)
2302                         {
2303                                 if(this.Common.Chart.IsDesignMode())
2304                                 {
2305                     LegendItem item = new LegendItem(this.Name + " - " + SR.DescriptionTypeEmpty, Color.White, "");
2306                                         item.ImageStyle = LegendImageStyle.Line;
2307                                         legendItems.Add(item);
2308                                 }
2309                         }
2310
2311                         // Add legend item cells based on predefined columns
2312                         foreach(LegendItem item in this.legendItems)
2313                         {
2314                                 item.AddAutomaticCells(this);
2315                         }
2316
2317                 }
2318
2319                 #endregion
2320
2321                 #region Legend painting methods
2322
2323                 /// <summary>
2324                 /// Paints legend using chart graphics object.
2325                 /// </summary>
2326                 /// <param name="chartGraph">The graph provides drawing object to the display device. A Graphics object is associated with a specific device context.</param>
2327                 internal void Paint(ChartGraphics chartGraph )
2328                 {
2329                         // Reset some values
2330                         this._offset = Size.Empty;
2331                         this._itemColumns = 0;
2332                         this._horizontalSpaceLeft = 0;
2333                         this._verticalSpaceLeft = 0;
2334                         this._subColumnSizes = null;
2335                         this._numberOfRowsPerColumn = null;
2336                         this._cellHeights = null;
2337                         this.autofitFont = null;
2338                         this._autoFitFontSizeAdjustment = 0;
2339                         this._numberOfCells = -1;
2340                         this._numberOfLegendItemsToProcess = -1;
2341
2342                         // Do nothing if legend disabled
2343                         if(!this.IsEnabled() ||
2344                                 (this.MaximumAutoSize == 0f && this.Position.Auto))
2345                         {
2346                                 return;
2347                         }
2348
2349                         // Add all series legend into items collection and then add custom legend items
2350                         FillLegendItemsCollection();
2351
2352                         // Clear all legend item cells information
2353                         foreach(LegendItem legendItem in this.legendItems)
2354                         {
2355                                 foreach(LegendCell cell in legendItem.Cells)
2356                                 {
2357                                         cell.ResetCache();
2358                                 }
2359                         }
2360
2361                         // Call a notification event, so that legend items collection can be modified by user
2362             this.Common.Chart.CallOnCustomizeLegend(legendItems, this.Name);
2363
2364                         // Check if legend is empty
2365                         if(this.legendItems.Count == 0)
2366                         {
2367                                 return;
2368                         }
2369
2370                         //***********************************************************
2371                         //** RecalculateAxesScale legend information
2372                         //***********************************************************
2373                         this.RecalcLegendInfo(chartGraph);
2374
2375
2376                         
2377                         //***********************************************************
2378                         //** Paint legend
2379                         //***********************************************************
2380
2381                         // Call BackPaint event
2382                         if( Common.ProcessModePaint )
2383                         {
2384                                 // Draw legend background, border and shadow
2385                                 chartGraph.FillRectangleRel( 
2386                                         chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
2387                                         BackColor, 
2388                                         BackHatchStyle, 
2389                                         BackImage, 
2390                                         BackImageWrapMode, 
2391                                         BackImageTransparentColor,
2392                                         BackImageAlignment,
2393                                         BackGradientStyle, 
2394                                         BackSecondaryColor,
2395                                         BorderColor, 
2396                                         this.GetBorderSize(), 
2397                                         BorderDashStyle, 
2398                                         ShadowColor, 
2399                                         ShadowOffset,
2400                                         PenAlignment.Inset);
2401
2402                 Common.Chart.CallOnPrePaint(new ChartPaintEventArgs(this, chartGraph, Common, Position));
2403                         }
2404
2405                         if( Common.ProcessModeRegions )
2406                         {
2407                                 SelectLegendBackground();
2408                         }
2409
2410                         //***********************************************************
2411                         //** Draw legend header
2412                         //***********************************************************
2413
2414                         this.DrawLegendHeader(chartGraph);
2415
2416                         //***********************************************************
2417                         //** Draw legend title
2418                         //***********************************************************
2419
2420                         this.DrawLegendTitle(chartGraph);
2421
2422                         // Add legend title hot region
2423                         if( Common.ProcessModeRegions && !this._titlePosition.IsEmpty)
2424                         {
2425                                 Common.HotRegionsList.AddHotRegion(chartGraph.GetRelativeRectangle(this._titlePosition), this, ChartElementType.LegendTitle, true );
2426                         }
2427
2428                         //***********************************************************
2429                         //** Draw legend items
2430                         //***********************************************************
2431                         if(this._numberOfLegendItemsToProcess < 0)
2432                         {
2433                                 this._numberOfLegendItemsToProcess = this.legendItems.Count;
2434                         }
2435                         for(int itemIndex = 0; itemIndex < this._numberOfLegendItemsToProcess; itemIndex++)
2436                         {
2437                                 LegendItem legendItem = this.legendItems[itemIndex];
2438
2439                                 // Iterate through legend item cells
2440                                 for(int cellIndex = 0; cellIndex < legendItem.Cells.Count; cellIndex++)
2441                                 {
2442                                         // Get legend cell
2443                                         LegendCell legendCell = legendItem.Cells[cellIndex];
2444
2445                                         // Paint cell
2446                                         legendCell.Paint(
2447                                                 chartGraph, 
2448                                                 this._autoFitFontSizeAdjustment,
2449                                                 this.autofitFont,
2450                                                 this.singleWCharacterSize);
2451                                 }
2452
2453                                 // Paint legend item separator
2454                                 if(legendItem.SeparatorType != LegendSeparatorStyle.None && 
2455                                         legendItem.Cells.Count > 0)
2456                                 {
2457                                         // Calculate separator position
2458                                         Rectangle separatorPosition = Rectangle.Empty;
2459                                         separatorPosition.X = legendItem.Cells[0].cellPosition.Left;
2460
2461                                         // Find right most cell position excluding ovelapped cells that have negative size
2462                                         int right = 0;
2463                                         for(int index = legendItem.Cells.Count - 1; index >= 0; index--)
2464                                         {
2465                                                 right = legendItem.Cells[index].cellPosition.Right;
2466                                                 if(right > 0)
2467                                                 {
2468                                                         break;
2469                                                 }
2470                                         }
2471                                         separatorPosition.Width = right - separatorPosition.X;
2472                                         separatorPosition.Y = legendItem.Cells[0].cellPosition.Bottom;
2473                                         separatorPosition.Height = this.GetSeparatorSize(legendItem.SeparatorType).Height;
2474                                         separatorPosition.Intersect(this._legendItemsAreaPosition);
2475
2476                                         // Draw separator
2477                                         this.DrawSeparator(
2478                                                 chartGraph, 
2479                                                 legendItem.SeparatorType,
2480                                                 legendItem.SeparatorColor, 
2481                                                 true,
2482                                                 separatorPosition);
2483                                 }
2484                         }
2485
2486                         //***********************************************************
2487                         //** If legend items are in multiple columns draw vertical
2488                         //** separator
2489                         //***********************************************************
2490                         if(this.ItemColumnSeparator != LegendSeparatorStyle.None)
2491                         {
2492                                 Rectangle separatorRect = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
2493                                 separatorRect.Y += this.GetBorderSize() + this._titlePosition.Height;
2494                                 separatorRect.Height -= 2 * this.GetBorderSize() + this._titlePosition.Height;
2495                                 separatorRect.X += this.GetBorderSize() + this._offset.Width;
2496                                 separatorRect.Width = this.GetSeparatorSize(this.ItemColumnSeparator).Width;
2497                                 if(this._horizontalSpaceLeft > 0)
2498                                 {
2499                                         separatorRect.X += this._horizontalSpaceLeft / 2;
2500                                 }
2501
2502                                 // Check position
2503                                 if(separatorRect.Width > 0 && separatorRect.Height > 0)
2504                                 {
2505                                         // Iterate through all columns
2506                                         for(int columnIndex = 0; columnIndex < this._itemColumns; columnIndex++ )
2507                                         {
2508                                                 // Iterate through all sub-columns
2509                                                 int cellCount = this.GetNumberOfCells();
2510                                                 for(int subColumnIndex = 0; subColumnIndex < cellCount; subColumnIndex++ )
2511                                                 {
2512                                                         separatorRect.X += this._subColumnSizes[columnIndex, subColumnIndex];
2513                                                 }
2514
2515                                                 // Draw separator if not the last column
2516                                                 if(columnIndex < this._itemColumns - 1)
2517                                                 {
2518                                                         this.DrawSeparator(chartGraph, this.ItemColumnSeparator, this.ItemColumnSeparatorColor, false, separatorRect);
2519                                                 }
2520
2521                                                 // Add separator width
2522                                                 separatorRect.X += separatorRect.Width;
2523                                         }
2524                                 }
2525                         }
2526
2527                         //***********************************************************
2528                         //** Draw special indicator on the bottom of the legend if 
2529                         //** it was truncated.
2530                         //***********************************************************
2531                         if(this._legendItemsTruncated &&
2532                                 this._legendItemsAreaPosition.Height > this._truncatedDotsSize / 2)
2533                         {
2534                                 // Calculate dots step (no more than 10 pixel)
2535                                 int markerCount = 3;
2536                                 int step = (this._legendItemsAreaPosition.Width / 3) / markerCount;
2537                                 step = (int)Math.Min(step, 10);
2538
2539                                 // Calculate start point
2540                                 PointF  point = new PointF(
2541                                         this._legendItemsAreaPosition.X + this._legendItemsAreaPosition.Width / 2 - step * (float)Math.Floor(markerCount/2f),
2542                                         this._legendItemsAreaPosition.Bottom + (this._truncatedDotsSize + this._offset.Height) / 2);
2543
2544                                 // Draw several dots at the bottom of the legend
2545                                 for(int index = 0; index < markerCount; index++)
2546                                 {
2547                                         chartGraph.DrawMarkerRel(
2548                                                 chartGraph.GetRelativePoint(point),
2549                                                 MarkerStyle.Circle,
2550                                                 this._truncatedDotsSize,
2551                                                 this.ForeColor,
2552                                                 Color.Empty,
2553                                                 0,
2554                                                 string.Empty,
2555                                                 Color.Empty,
2556                                                 0,
2557                                                 Color.Empty,
2558                                                 RectangleF.Empty);
2559
2560                                         // Shift to the right
2561                                         point.X += step;
2562                                 }
2563
2564                         }
2565
2566
2567                         // Call Paint event
2568                         if( Common.ProcessModePaint )
2569                         {
2570                 Common.Chart.CallOnPostPaint(new ChartPaintEventArgs(this, chartGraph, Common, Position));
2571                         }
2572                                                 
2573                         // Remove temporary cells from legend items
2574                         foreach(LegendItem legendItem in this.legendItems)
2575                         {
2576                                 if(legendItem.clearTempCells)
2577                                 {
2578                                         legendItem.clearTempCells = false;
2579                                         legendItem.Cells.Clear();
2580                                 }
2581                         }
2582
2583                 }
2584
2585                 #endregion 
2586
2587                 #region Legend properties
2588
2589                 /// <summary>
2590                 /// Gets or sets the name of the legend.
2591                 /// </summary>
2592                 [
2593                 SRCategory("CategoryAttributeMisc"),
2594                 Bindable(true),
2595                 SRDescription("DescriptionAttributeLegend_Name"),
2596                 NotifyParentPropertyAttribute(true),
2597                 #if !Microsoft_CONTROL
2598                 PersistenceMode(PersistenceMode.Attribute),
2599                 #endif
2600                 ]
2601                 public override string Name
2602                 {
2603                         get
2604                         {
2605                                 return base.Name;
2606                         }
2607                         set
2608                         {
2609                 base.Name = value;
2610                         }
2611                 }
2612
2613                 /// <summary>
2614                 /// Gets or sets the name of the chart area where the legend
2615         /// should be docked.
2616                 /// </summary>
2617                 [
2618                 SRCategory("CategoryAttributeDocking"),
2619                 Bindable(true),
2620         DefaultValue(Constants.NotSetValue),
2621                 SRDescription("DescriptionAttributeLegend_DockToChartArea"),
2622         TypeConverter(typeof(LegendAreaNameConverter)),
2623                 NotifyParentPropertyAttribute(true),
2624                 #if !Microsoft_CONTROL
2625                 PersistenceMode(PersistenceMode.Attribute),
2626                 #endif
2627                 ]
2628                 public string DockedToChartArea
2629                 {
2630                         get
2631                         {
2632                                 return _dockedToChartArea;
2633                         }
2634                         set
2635                         {
2636                                 if(value != _dockedToChartArea)
2637                                 {
2638                                         if (String.IsNullOrEmpty(value))
2639                                         {
2640                         _dockedToChartArea = Constants.NotSetValue;
2641                                         }
2642                                         else
2643                                         {
2644                         if (Chart != null && Chart.ChartAreas != null)
2645                         {
2646                             Chart.ChartAreas.VerifyNameReference(value);
2647                         }
2648                                                 _dockedToChartArea = value;
2649                                         }
2650                                         this.Invalidate(false);
2651                                 }
2652                         }
2653                 }
2654
2655                 /// <summary>
2656                 /// Gets or sets a property which indicates whether 
2657         /// the legend is docked inside the chart area.  
2658         /// This property is only available when DockedToChartArea is set.
2659                 /// </summary>
2660                 [
2661         SRCategory("CategoryAttributeDocking"),
2662                 Bindable(true),
2663                 DefaultValue(true),
2664                 SRDescription("DescriptionAttributeLegend_DockInsideChartArea"),
2665                 NotifyParentPropertyAttribute(true),
2666                 #if !Microsoft_CONTROL
2667                 PersistenceMode(PersistenceMode.Attribute),
2668                 #endif
2669                 ]
2670                 public bool IsDockedInsideChartArea
2671                 {
2672                         get
2673                         {
2674                                 return _isDockedInsideChartArea;
2675                         }
2676                         set
2677                         {
2678                                 if(value != _isDockedInsideChartArea)
2679                                 {
2680                                         _isDockedInsideChartArea = value;
2681                                         this.Invalidate(false);
2682                                 }
2683                         }
2684                 }
2685
2686                 /// <summary>
2687         /// Gets or sets the position of the legend.
2688                 /// </summary>
2689                 [
2690                 SRCategory("CategoryAttributeAppearance"),
2691                 Bindable(true),
2692                 SRDescription("DescriptionAttributeLegend_Position"),
2693 #if Microsoft_CONTROL
2694                 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
2695 #else
2696                 PersistenceMode(PersistenceMode.InnerProperty),
2697 #endif
2698                 NotifyParentPropertyAttribute(true),
2699                 TypeConverter(typeof(ElementPositionConverter)),
2700                 SerializationVisibilityAttribute(SerializationVisibility.Element)
2701                 ]
2702                 public ElementPosition Position
2703                 {
2704                         get
2705                         {       
2706                                 // Serialize only position values if Auto set to false
2707                 if (this.Common != null && this.Common.Chart != null && this.Common.Chart.serializationStatus == SerializationStatus.Saving)
2708                                 {
2709                                         if(_position.Auto)
2710                                         {
2711                                                 return new ElementPosition();   
2712                                         }
2713                                         else
2714                                         {
2715                                                 ElementPosition newPosition = new ElementPosition();
2716 #if Microsoft_CONTROL
2717                                                 newPosition.Auto = false;
2718 #else
2719                                                 newPosition.Auto = true;
2720 #endif
2721                                                 newPosition.SetPositionNoAuto(_position.X, _position.Y, _position.Width, _position.Height);
2722                                                 return newPosition;
2723                                         }
2724                                 }
2725                                 return _position;
2726                         }
2727                         set
2728                         {
2729                                 _position = value;
2730                                 this.Invalidate(false);
2731                         }
2732                 }
2733
2734         /// <summary>
2735         /// Determoines if this position should be serialized.
2736         /// </summary>
2737         /// <returns></returns>
2738         internal bool ShouldSerializePosition()
2739         {
2740             return !this.Position.Auto;
2741         }
2742
2743
2744                 /// <summary>
2745                 /// Gets or sets a property which indicates whether 
2746         /// all legend items are equally spaced.
2747                 /// </summary>
2748                 [
2749                 SRCategory("CategoryAttributeAppearance"),
2750                 Bindable(true),
2751                 DefaultValue(false),
2752                 SRDescription("DescriptionAttributeLegend_EquallySpacedItems"),
2753                 NotifyParentPropertyAttribute(true),
2754                 #if !Microsoft_CONTROL
2755                 PersistenceMode(PersistenceMode.Attribute)
2756                 #endif
2757                 ]
2758                 public bool IsEquallySpacedItems
2759                 {
2760                         get
2761                         {
2762                                 return _isEquallySpacedItems;
2763                         }
2764                         set
2765                         {
2766                                 _isEquallySpacedItems = value;
2767                                 this.Invalidate(false);
2768                         }
2769                 }
2770
2771                 /// <summary>
2772                 /// Gets or sets a flag which indicates whether the legend is enabled.
2773                 /// </summary>
2774                 [
2775                 SRCategory("CategoryAttributeAppearance"),
2776                 Bindable(true),
2777                 DefaultValue(true),
2778                 SRDescription("DescriptionAttributeLegend_Enabled"),
2779                 NotifyParentPropertyAttribute(true),
2780                 ParenthesizePropertyNameAttribute(true),
2781                 #if !Microsoft_CONTROL
2782                 PersistenceMode(PersistenceMode.Attribute)
2783                 #endif
2784                 ]
2785                 public bool Enabled
2786                 {
2787                         get
2788                         {
2789                                 return _enabled;
2790                         }
2791                         set
2792                         {
2793                                 _enabled = value;
2794                                 this.Invalidate(false);
2795                         }
2796                 }
2797
2798                 /// <summary>
2799         /// Gets or sets a value that indicates if legend text is automatically sized.
2800                 /// </summary>
2801                 [
2802                 SRCategory("CategoryAttributeAppearance"),
2803                 Bindable(true),
2804                 DefaultValue(true),
2805                 SRDescription("DescriptionAttributeLegend_AutoFitText"),
2806                 NotifyParentPropertyAttribute(true),
2807                 #if !Microsoft_CONTROL
2808                 PersistenceMode(PersistenceMode.Attribute)
2809                 #endif
2810                 ]
2811                 public bool IsTextAutoFit
2812                 {
2813                         get
2814                         {
2815                                 return _isTextAutoFit;
2816                         }
2817                         set
2818                         {
2819                                 _isTextAutoFit = value;
2820
2821                                 if(_isTextAutoFit)
2822                                 {
2823                                         // Reset the font size to "8"
2824                                         // Use current font family name ans style if possible.
2825                                         if(_font != null)
2826                                         {
2827                         _font = _fontCache.GetFont(_font.FontFamily, 8, _font.Style); ;
2828                                         }
2829                                         else
2830                                         {
2831                                                 _font = _fontCache.DefaultFont;
2832                                         }
2833                                 }
2834
2835                                 this.Invalidate(false);
2836                         }
2837                 }
2838
2839                 /// <summary>
2840                 /// Gets or sets the legend style.
2841                 /// </summary>
2842                 [
2843                 SRCategory("CategoryAttributeAppearance"),
2844                 Bindable(true),
2845                 DefaultValue(LegendStyle.Table),
2846                 SRDescription("DescriptionAttributeLegend_LegendStyle"),
2847                 NotifyParentPropertyAttribute(true),
2848                 ParenthesizePropertyNameAttribute(true),
2849                 #if !Microsoft_CONTROL
2850                 PersistenceMode(PersistenceMode.Attribute)
2851                 #endif
2852                 ]
2853                 public LegendStyle LegendStyle
2854                 {
2855                         get
2856                         {
2857                                 return _legendStyle;
2858                         }
2859                         set
2860                         {
2861                                 _legendStyle = value;
2862                                 this.Invalidate(false);
2863                         }
2864                 }
2865
2866
2867                 /// <summary>
2868         /// Gets or sets the minimum font size that can be used by the legend text's auto-fitting algorithm. 
2869                 /// </summary>
2870                 [
2871                 SRCategory("CategoryAttributeAppearance"),
2872                 DefaultValue(7),
2873                 SRDescription("DescriptionAttributeLegend_AutoFitMinFontSize"),
2874                 ]
2875                 public int AutoFitMinFontSize
2876                 {
2877                         get
2878                         {
2879                                 return this._autoFitMinFontSize;
2880                         }
2881                         set
2882                         {
2883                                 // Font size cannot be less than 5
2884                                 if(value < 5)
2885                                 {
2886                     throw (new InvalidOperationException(SR.ExceptionLegendAutoFitMinFontSizeInvalid));
2887                                 }
2888
2889                                 this._autoFitMinFontSize = value;
2890                                 this.Invalidate(false);
2891                         }
2892                 }
2893
2894         /// <summary>
2895         /// Gets or sets the maximum size (in percentage) of the legend used in the automatic layout algorithm.
2896         /// </summary>
2897         /// <remarks>
2898         /// If the legend is docked to the left or right, this property determines the maximum width of the legend, measured as a percentage.
2899         /// If the legend is docked to the top or bottom, this property determines the maximum height of the legend, measured as a percentage.
2900         /// </remarks>
2901                 [
2902                 SRCategory("CategoryAttributeDocking"),
2903                 DefaultValue(50f),
2904                 SRDescription("DescriptionAttributeLegend_MaxAutoSize"),
2905                 ]
2906                 public float MaximumAutoSize
2907                 {
2908                         get
2909                         {
2910                 return this._maximumLegendAutoSize;
2911                         }
2912                         set
2913                         {
2914                                 if(value < 0f || value > 100f)
2915                                 {
2916                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendMaximumAutoSizeInvalid));
2917                                 }
2918                 this._maximumLegendAutoSize = value;
2919                                 this.Invalidate(false);
2920                         }
2921                 }
2922
2923                 /// <summary>
2924                 /// Gets a collection of legend columns.
2925                 /// </summary>
2926                 [
2927                 SRCategory("CategoryAttributeCellColumns"),
2928                 SRDescription("DescriptionAttributeLegend_CellColumns"),
2929 #if Microsoft_CONTROL
2930                 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
2931 #else
2932                 PersistenceMode(PersistenceMode.InnerProperty),
2933 #endif
2934         Editor(Editors.LegendCellColumnCollectionEditor.Editor, Editors.LegendCellColumnCollectionEditor.Base),
2935                 ]
2936                 public LegendCellColumnCollection CellColumns
2937                 {
2938                         get
2939                         {
2940                                 return this._cellColumns;
2941                         }
2942                 }
2943
2944                 /// <summary>
2945                 /// Gets the legend table style.
2946                 /// </summary>
2947                 [
2948                 SRCategory("CategoryAttributeAppearance"),
2949                 Bindable(true),
2950                 DefaultValue(LegendTableStyle.Auto),
2951                 SRDescription("DescriptionAttributeLegend_TableStyle"),
2952                 NotifyParentPropertyAttribute(true),
2953                 ParenthesizePropertyNameAttribute(true),
2954                 #if !Microsoft_CONTROL
2955                 PersistenceMode(PersistenceMode.Attribute)
2956                 #endif
2957                 ]
2958                 public LegendTableStyle TableStyle
2959                 {
2960                         get
2961                         {
2962                                 return this._legendTableStyle;
2963                         }
2964                         set
2965                         {
2966                                 this._legendTableStyle = value;
2967                                 this.Invalidate(false);
2968                         }
2969                 }
2970
2971                 /// <summary>
2972                 /// Gets the legend header separator style.
2973                 /// </summary>
2974                 [
2975                 SRCategory("CategoryAttributeCellColumns"),
2976                 DefaultValue(typeof(LegendSeparatorStyle), "None"),
2977                 SRDescription("DescriptionAttributeLegend_HeaderSeparator"),
2978                 ]
2979                 public LegendSeparatorStyle HeaderSeparator
2980                 {
2981                         get
2982                         {
2983                                 return this._headerSeparator;
2984                         }
2985                         set
2986                         {
2987                                 if(value != this._headerSeparator)
2988                                 {
2989                                         this._headerSeparator = value;
2990                                         this.Invalidate(false);
2991                                 }
2992                         }
2993                 }
2994
2995                 /// <summary>
2996                 /// Gets or sets the color of the legend header separator.
2997                 /// </summary>
2998                 [
2999                 SRCategory("CategoryAttributeCellColumns"),
3000                 DefaultValue(typeof(Color), "Black"),
3001                 SRDescription("DescriptionAttributeLegend_HeaderSeparatorColor"),
3002         TypeConverter(typeof(ColorConverter)),
3003         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3004                 ]
3005                 public Color HeaderSeparatorColor
3006                 {
3007                         get
3008                         {
3009                                 return this._headerSeparatorColor;
3010                         }
3011                         set
3012                         {
3013                                 if(value != this._headerSeparatorColor)
3014                                 {
3015                                         this._headerSeparatorColor = value;
3016                                         this.Invalidate(false);
3017                                 }
3018                         }
3019                 }
3020
3021                 /// <summary>
3022         /// Gets or sets the separator style of the legend table columns.
3023                 /// </summary>
3024                 [
3025                 SRCategory("CategoryAttributeCellColumns"),
3026                 DefaultValue(typeof(LegendSeparatorStyle), "None"),
3027                 SRDescription("DescriptionAttributeLegend_ItemColumnSeparator"),
3028                 ]
3029                 public LegendSeparatorStyle ItemColumnSeparator
3030                 {
3031                         get
3032                         {
3033                                 return this._itemColumnSeparator;
3034                         }
3035                         set
3036                         {
3037                                 if(value != this._itemColumnSeparator)
3038                                 {
3039                                         this._itemColumnSeparator = value;
3040                                         this.Invalidate(false);
3041                                 }
3042                         }
3043                 }
3044
3045                 /// <summary>
3046         /// Gets or sets the color of the separator of the legend table columns.
3047                 /// </summary>
3048                 [
3049                 SRCategory("CategoryAttributeCellColumns"),
3050                 DefaultValue(typeof(Color), "Black"),
3051                 SRDescription("DescriptionAttributeLegend_ItemColumnSeparatorColor"),
3052         TypeConverter(typeof(ColorConverter)),
3053         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3054                 ]
3055                 public Color ItemColumnSeparatorColor
3056                 {
3057                         get
3058                         {
3059                                 return this._itemColumnSeparatorColor;
3060                         }
3061                         set
3062                         {
3063                                 if(value != this._itemColumnSeparatorColor)
3064                                 {
3065                                         this._itemColumnSeparatorColor = value;
3066                                         this.Invalidate(false);
3067                                 }
3068                         }
3069                 }
3070
3071
3072                 /// <summary>
3073                 /// Gets or sets the legend table column spacing, as a percentage of the legend text font.
3074                 /// </summary>
3075                 [
3076                 SRCategory("CategoryAttributeCellColumns"),
3077                 DefaultValue(50),
3078                 SRDescription("DescriptionAttributeLegend_ItemColumnSpacing"),
3079                 ]
3080                 public int ItemColumnSpacing
3081                 {
3082                         get
3083                         {
3084                                 return this._itemColumnSpacing;
3085                         }
3086                         set
3087                         {
3088                                 if(value != this._itemColumnSpacing)
3089                                 {
3090                                         if(value < 0)
3091                                         {
3092                         throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendColumnSpacingInvalid));
3093                                         }
3094                                         this._itemColumnSpacing = value;
3095                                         this.Invalidate(false);
3096                                 }
3097                         }
3098                 }
3099
3100
3101
3102                 /// <summary>
3103                 /// Gets or sets the legend background color.
3104                 /// </summary>
3105                 [
3106                 DefaultValue(typeof(Color), ""),
3107         SRCategory("CategoryAttributeAppearance"),
3108                 Bindable(true),
3109         SRDescription("DescriptionAttributeBackColor"),
3110                 NotifyParentPropertyAttribute(true),
3111         TypeConverter(typeof(ColorConverter)),
3112         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3113                 #if !Microsoft_CONTROL
3114                 PersistenceMode(PersistenceMode.Attribute)
3115                 #endif
3116                 ]
3117                 public Color BackColor
3118                 {
3119                         get
3120                         {
3121                                 return _backColor;
3122                         }
3123                         set
3124                         {
3125                                 _backColor = value;
3126                                 this.Invalidate(false);
3127                         }
3128                 }
3129
3130                 /// <summary>
3131                 /// Gets or sets the legend border color.
3132                 /// </summary>
3133                 [
3134                 DefaultValue(typeof(Color), ""),
3135                 SRCategory("CategoryAttributeAppearance"),
3136                 Bindable(true),
3137         SRDescription("DescriptionAttributeBorderColor"),
3138                 NotifyParentPropertyAttribute(true),
3139         TypeConverter(typeof(ColorConverter)),
3140         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3141                 #if !Microsoft_CONTROL
3142                 PersistenceMode(PersistenceMode.Attribute)
3143                 #endif
3144                 ]
3145                 public Color BorderColor
3146                 {
3147                         get
3148                         {
3149                                 return _borderColor;
3150                         }
3151                         set
3152                         {
3153                                 _borderColor = value;
3154                                 this.Invalidate(false);
3155                         }
3156                 }
3157
3158                 /// <summary>
3159                 /// Gets or sets the legend border style.
3160                 /// </summary>
3161                 [
3162
3163                 SRCategory("CategoryAttributeAppearance"),
3164                 Bindable(true),
3165                 DefaultValue(ChartDashStyle.Solid),
3166         SRDescription("DescriptionAttributeBorderDashStyle"),
3167                 NotifyParentPropertyAttribute(true),
3168                 #if !Microsoft_CONTROL
3169                 PersistenceMode(PersistenceMode.Attribute)
3170                 #endif
3171                 ]
3172                 public ChartDashStyle BorderDashStyle
3173                 {
3174                         get
3175                         {
3176                                 return _borderDashStyle;
3177                         }
3178                         set
3179                         {
3180                                 _borderDashStyle = value;
3181                                 this.Invalidate(false);
3182                         }
3183                 }
3184
3185                 /// <summary>
3186                 /// Gets or sets the legend border width.
3187                 /// </summary>
3188                 [
3189
3190                 SRCategory("CategoryAttributeAppearance"),
3191                 Bindable(true),
3192                 DefaultValue(1),
3193         SRDescription("DescriptionAttributeBorderWidth"),
3194                 NotifyParentPropertyAttribute(true),
3195                 #if !Microsoft_CONTROL
3196                 PersistenceMode(PersistenceMode.Attribute)
3197                 #endif
3198                 ]
3199                 public int BorderWidth
3200                 {
3201                         get
3202                         {
3203                                 return _borderWidth;
3204                         }
3205                         set
3206                         {
3207                                 if(value < 0)
3208                                 {
3209                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendBorderWidthIsNegative));
3210                                 }
3211                                 _borderWidth = value;
3212                                 this.Invalidate(false);
3213                         }
3214                 }
3215                 
3216                 /// <summary>
3217                 /// Gets or sets the legend background image.
3218                 /// </summary>
3219                 [
3220                 SRCategory("CategoryAttributeAppearance"),
3221                 Bindable(true),
3222                 DefaultValue(""),
3223         SRDescription("DescriptionAttributeBackImage"),
3224         Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
3225                 #if !Microsoft_CONTROL
3226                 PersistenceMode(PersistenceMode.Attribute),
3227                 #endif
3228                 NotifyParentPropertyAttribute(true),
3229                 ]
3230                 public string BackImage
3231                 {
3232                         get
3233                         {
3234                                 return _backImage;
3235                         }
3236                         set
3237                         {
3238                                 _backImage = value;
3239                                 this.Invalidate(true);
3240                         }
3241                 }
3242
3243                 /// <summary>
3244                 /// Gets or sets the legend background image drawing mode.
3245                 /// </summary>
3246                 [
3247                 SRCategory("CategoryAttributeAppearance"),
3248                 Bindable(true),
3249                 DefaultValue(ChartImageWrapMode.Tile),
3250                 NotifyParentPropertyAttribute(true),
3251         SRDescription("DescriptionAttributeImageWrapMode"),
3252                 #if !Microsoft_CONTROL
3253                 PersistenceMode(PersistenceMode.Attribute)
3254                 #endif
3255                 ]
3256                 public ChartImageWrapMode BackImageWrapMode
3257                 {
3258                         get
3259                         {
3260                                 return _backImageWrapMode;
3261                         }
3262                         set
3263                         {
3264                                 _backImageWrapMode = value;
3265                                 this.Invalidate(true);
3266                         }
3267                 }
3268
3269                 /// <summary>
3270         /// Gets or sets a color which will be replaced with a transparent color while drawing the background image.
3271                 /// </summary>
3272                 [
3273                 SRCategory("CategoryAttributeAppearance"),
3274                 Bindable(true),
3275                 DefaultValue(typeof(Color), ""),
3276                 NotifyParentPropertyAttribute(true),
3277         SRDescription("DescriptionAttributeImageTransparentColor"),
3278         TypeConverter(typeof(ColorConverter)),
3279         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3280                 #if !Microsoft_CONTROL
3281                 PersistenceMode(PersistenceMode.Attribute)
3282                 #endif
3283                 ]
3284                 public Color BackImageTransparentColor
3285                 {
3286                         get
3287                         {
3288                                 return _backImageTransparentColor;
3289                         }
3290                         set
3291                         {
3292                                 _backImageTransparentColor = value;
3293                                 this.Invalidate(true);
3294                         }
3295                 }
3296
3297                 /// <summary>
3298                 /// Gets or sets the background image alignment used for the unscaled drawing mode.
3299                 /// </summary>
3300                 [
3301                 SRCategory("CategoryAttributeAppearance"),
3302                 Bindable(true),
3303                 DefaultValue(ChartImageAlignmentStyle.TopLeft),
3304                 NotifyParentPropertyAttribute(true),
3305         SRDescription("DescriptionAttributeBackImageAlign"),
3306                 #if !Microsoft_CONTROL
3307                 PersistenceMode(PersistenceMode.Attribute)
3308                 #endif
3309                 ]
3310                 public ChartImageAlignmentStyle BackImageAlignment
3311                 {
3312                         get
3313                         {
3314                                 return _backImageAlignment;
3315                         }
3316                         set
3317                         {
3318                                 _backImageAlignment = value;
3319                                 this.Invalidate(true);
3320                         }
3321                 }
3322
3323                 /// <summary>
3324                 /// Gets or sets background gradient style of the legend.
3325                 /// </summary>
3326                 [
3327
3328                 SRCategory("CategoryAttributeAppearance"),
3329                 Bindable(true),
3330                 DefaultValue(GradientStyle.None),
3331                 NotifyParentPropertyAttribute(true),
3332         SRDescription("DescriptionAttributeBackGradientStyle"),
3333                 #if !Microsoft_CONTROL
3334                 PersistenceMode(PersistenceMode.Attribute),
3335                 #endif
3336         Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
3337
3338                 ]
3339                 public GradientStyle BackGradientStyle
3340                 {
3341                         get
3342                         {
3343                                 return _backGradientStyle;
3344                         }
3345                         set
3346                         {
3347                                 _backGradientStyle = value;
3348                                 this.Invalidate(true);
3349                         }
3350                 }
3351
3352         /// <summary>
3353         /// Gets or sets the secondary background color.
3354         /// <seealso cref="BackColor"/>
3355         /// <seealso cref="BackHatchStyle"/>
3356         /// <seealso cref="BackGradientStyle"/>
3357         /// </summary>
3358         /// <value>
3359         /// A <see cref="Color"/> value used for the secondary color of background with 
3360         /// hatching or gradient fill.
3361         /// </value>
3362         /// <remarks>
3363         /// This color is used with <see cref="BackColor"/> when <see cref="BackHatchStyle"/> or
3364         /// <see cref="BackGradientStyle"/> are used.
3365         /// </remarks>
3366                 [
3367
3368                 SRCategory("CategoryAttributeAppearance"),
3369                 Bindable(true),
3370                 DefaultValue(typeof(Color), ""),
3371                 NotifyParentPropertyAttribute(true),
3372         SRDescription("DescriptionAttributeBackSecondaryColor"),
3373         TypeConverter(typeof(ColorConverter)),
3374         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3375                 #if !Microsoft_CONTROL
3376                 PersistenceMode(PersistenceMode.Attribute)
3377                 #endif
3378                 ]
3379                 public Color BackSecondaryColor
3380                 {
3381                         get
3382                         {
3383                                 return _backSecondaryColor;
3384                         }
3385                         set
3386                         {
3387                                 _backSecondaryColor = value;
3388                                 this.Invalidate(true);
3389                         }
3390                 }
3391
3392         /// <summary>
3393         /// Gets or sets the background hatch style.
3394         /// <seealso cref="BackSecondaryColor"/>
3395         /// <seealso cref="BackColor"/>
3396         /// <seealso cref="BackGradientStyle"/>
3397         /// </summary>
3398         /// <value>
3399         /// A <see cref="ChartHatchStyle"/> value used for the background.
3400         /// </value>
3401         /// <remarks>
3402         /// Two colors are used to draw the hatching, <see cref="BackColor"/> and <see cref="BackSecondaryColor"/>.
3403         /// </remarks>
3404                 [
3405
3406         SRCategory("CategoryAttributeAppearance"),
3407                 Bindable(true),
3408                 DefaultValue(ChartHatchStyle.None),
3409                 NotifyParentPropertyAttribute(true),
3410         SRDescription("DescriptionAttributeBackHatchStyle"),
3411                 #if !Microsoft_CONTROL
3412                 PersistenceMode(PersistenceMode.Attribute),
3413                 #endif
3414         Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
3415                 ]
3416                 public ChartHatchStyle BackHatchStyle
3417                 {
3418                         get
3419                         {
3420                                 return _backHatchStyle;
3421                         }
3422                         set
3423                         {
3424                                 _backHatchStyle = value;
3425                                 this.Invalidate(true);
3426                         }
3427                 }
3428
3429                 /// <summary>
3430                 /// Gets or sets the font of the legend text.
3431                 /// </summary>
3432                 [
3433
3434                 SRCategory("CategoryAttributeAppearance"),
3435                 Bindable(true),
3436                 DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
3437                 SRDescription("DescriptionAttributeLegend_Font"),
3438                 NotifyParentPropertyAttribute(true),
3439                 #if !Microsoft_CONTROL
3440                 PersistenceMode(PersistenceMode.Attribute)
3441                 #endif
3442                 ]
3443                 public Font Font
3444                 {
3445                         get
3446                         {
3447                                 return _font;
3448                         }
3449                         set
3450                         {
3451                                 this.IsTextAutoFit = false;
3452
3453                                 _font = value;
3454                                 this.Invalidate(false);
3455                         }
3456                 }
3457
3458                 /// <summary>
3459                 /// Gets or sets the color of the legend text.
3460                 /// </summary>
3461                 [
3462
3463                 SRCategory("CategoryAttributeAppearance"),
3464                 Bindable(true),
3465                 DefaultValue(typeof(Color), "Black"),
3466         SRDescription("DescriptionAttributeLegendFontColor"),
3467                 NotifyParentPropertyAttribute(true),
3468         TypeConverter(typeof(ColorConverter)),
3469         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3470                 #if !Microsoft_CONTROL
3471                 PersistenceMode(PersistenceMode.Attribute)
3472                 #endif
3473                 ]
3474                 public Color ForeColor
3475                 {
3476                         get
3477                         {
3478                                 return _foreColor;
3479                         }
3480                         set
3481                         {
3482                                 _foreColor = value;
3483                                 this.Invalidate(true);
3484                         }
3485                 }
3486
3487                 /// <summary>
3488                 /// Gets or sets the text alignment.
3489                 /// </summary>
3490                 [
3491                 SRCategory("CategoryAttributeDocking"),
3492                 Bindable(true),
3493                 DefaultValue(StringAlignment.Near),
3494                 SRDescription("DescriptionAttributeLegend_Alignment"),
3495                 NotifyParentPropertyAttribute(true),
3496                 #if !Microsoft_CONTROL
3497                 PersistenceMode(PersistenceMode.Attribute)
3498                 #endif
3499                 ]
3500                 public StringAlignment Alignment
3501                 {
3502                         get
3503                         {
3504                                 return _legendAlignment;
3505                         }
3506                         set
3507                         {
3508                                 _legendAlignment = value;
3509                                 this.Invalidate(false);
3510                         }
3511                 }
3512                 
3513                 /// <summary>
3514                 /// Gets or sets the property that specifies where the legend docks.
3515                 /// </summary>
3516                 [
3517         SRCategory("CategoryAttributeDocking"),
3518                 Bindable(true),
3519                 DefaultValue(Docking.Right),
3520                 SRDescription("DescriptionAttributeLegend_Docking"),
3521                 NotifyParentPropertyAttribute(true),
3522                 #if !Microsoft_CONTROL
3523                 PersistenceMode(PersistenceMode.Attribute)
3524                 #endif
3525                 ]
3526                 public Docking Docking
3527                 {
3528                         get
3529                         {
3530                                 return _legendDocking;
3531                         }
3532                         set
3533                         {
3534                                 _legendDocking = value;
3535                                 this.Invalidate(false);
3536                         }
3537                 }
3538
3539         /// <summary>
3540         /// Gets or sets the offset between the legend and its shadow.
3541         /// <seealso cref="ShadowColor"/>
3542         /// </summary>
3543         /// <value>
3544         /// An integer value that represents the offset between the legend and its shadow.
3545         /// </value>
3546                 [
3547                 SRCategory("CategoryAttributeAppearance"),
3548                 Bindable(true),
3549                 DefaultValue(0),
3550         SRDescription("DescriptionAttributeShadowOffset"),
3551                 NotifyParentPropertyAttribute(true),
3552                 #if !Microsoft_CONTROL
3553                 PersistenceMode(PersistenceMode.Attribute)
3554                 #endif
3555                 ]
3556                 public int ShadowOffset
3557                 {
3558                         get
3559                         {
3560                                 return _shadowOffset;
3561                         }
3562                         set
3563                         {
3564                                 _shadowOffset = value;
3565                                 this.Invalidate(false);
3566                         }
3567                 }
3568
3569         /// <summary>
3570         /// Gets or sets the color of a legend's shadow.
3571         /// <seealso cref="ShadowOffset"/>
3572         /// </summary>
3573         /// <value>
3574         /// A <see cref="Color"/> value used to draw a legend's shadow.
3575         /// </value>
3576                 [
3577                 SRCategory("CategoryAttributeAppearance"),
3578                 Bindable(true),
3579                 DefaultValue(typeof(Color), "128, 0, 0, 0"),
3580         SRDescription("DescriptionAttributeShadowColor"),
3581                 NotifyParentPropertyAttribute(true),
3582         TypeConverter(typeof(ColorConverter)),
3583         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3584                 #if !Microsoft_CONTROL
3585                 PersistenceMode(PersistenceMode.Attribute)
3586                 #endif
3587                 ]
3588                 public Color ShadowColor
3589                 {
3590                         get
3591                         {
3592                                 return _shadowColor;
3593                         }
3594                         set
3595                         {
3596                                 _shadowColor = value;
3597                                 this.Invalidate(true);
3598                         }
3599                 }
3600
3601                 /// <summary>
3602                 /// Gets or sets the name of the chart area name inside which the legend is drawn.
3603                 /// </summary>
3604                 [
3605                 SRCategory("CategoryAttributeAppearance"),
3606                 Browsable(false),
3607                 Bindable(false),
3608         DefaultValue(Constants.NotSetValue),
3609                 NotifyParentPropertyAttribute(true),
3610                 SRDescription("DescriptionAttributeLegend_InsideChartArea"),
3611                 EditorBrowsableAttribute(EditorBrowsableState.Never),
3612                 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content),
3613                 SerializationVisibilityAttribute(SerializationVisibility.Hidden),
3614                 TypeConverter(typeof(LegendAreaNameConverter))
3615                 ]
3616                 public string InsideChartArea
3617                 {
3618                         get
3619                         {
3620                                 if(this.Common != null && 
3621                                         this.Common.Chart != null &&
3622                                         this.Common.Chart.serializing)
3623                                 {
3624                                         return "NotSet";
3625                                 }
3626                                 return this.DockedToChartArea;
3627                         }
3628                         set
3629                         {
3630                                 if(value.Length == 0)
3631                                 {
3632                     this.DockedToChartArea = Constants.NotSetValue;
3633                                 }
3634                                 else
3635                                 {
3636                                         this.DockedToChartArea = value;
3637                                 }
3638                                 this.Invalidate(false);
3639                         }
3640                 }
3641
3642
3643                 /// <summary>
3644                 /// Gets the custom legend items.
3645                 /// </summary>
3646                 [
3647                 SRCategory("CategoryAttributeAppearance"),
3648                 Bindable(true),
3649                 NotifyParentPropertyAttribute(true),
3650                 SRDescription("DescriptionAttributeLegend_CustomItems"),
3651 #if Microsoft_CONTROL
3652                 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
3653 #else
3654                 PersistenceMode(PersistenceMode.InnerProperty),
3655 #endif
3656         Editor(Editors.LegendItemCollectionEditor.Editor, Editors.LegendItemCollectionEditor.Base),
3657                 ]
3658                 public LegendItemsCollection CustomItems
3659                 {
3660                         get
3661                         {
3662                                 return _customLegends;
3663                         }
3664                 }
3665
3666
3667
3668                 /// <summary>
3669                 /// Gets or sets a property that defines the preferred number of characters in a line of the legend text.
3670                 /// </summary>
3671                 /// <remarks>
3672                 /// When legend text exceeds the value defined in the <b>TextWrapThreshold</b> property, it will be
3673                 /// automatically wrapped on the next whitespace. Text will not be wrapped if there is no whitespace
3674                 /// characters in the text. Set this property to zero to disable the feature.
3675                 /// </remarks>
3676                 [
3677                 SRCategory("CategoryAttributeAppearance"),
3678                 DefaultValue(25),
3679                 SRDescription("DescriptionAttributeLegend_TextWrapThreshold"),
3680                 ]
3681                 public int TextWrapThreshold
3682                 {
3683                         get
3684                         {
3685                                 return this._textWrapThreshold;
3686                         }
3687                         set
3688                         {
3689                                 if(value != this._textWrapThreshold)
3690                                 {
3691                                         if(value < 0)
3692                                         {
3693                         throw (new ArgumentException(SR.ExceptionTextThresholdIsNegative, "value"));
3694                                         }
3695                                         this._textWrapThreshold = value;
3696                                         this.Invalidate(false);
3697                                 }
3698                         }
3699                 }
3700
3701                 /// <summary>
3702                 /// Gets or sets a property that specifies the order that legend items are shown. This property only affects 
3703                 /// legend items automatically added for the chart series and has no effect on custom legend items.
3704                 /// </summary>
3705                 /// <remarks>
3706                 /// When the <b>LegendItemOrder</b> property is set to <b>Auto</b>, the legend will automatically be reversed 
3707                 /// if StackedColumn, StackedColumn100, StackedArea or StackedArea100 chart types are used.
3708                 /// </remarks>
3709                 [
3710                 SRCategory("CategoryAttributeAppearance"),
3711         DefaultValue(LegendItemOrder.Auto),
3712                 SRDescription("DescriptionAttributeLegend_Reversed"),
3713                 ]
3714         public LegendItemOrder LegendItemOrder
3715                 {
3716                         get
3717                         {
3718                                 return this._legendItemOrder;
3719                         }
3720                         set
3721                         {
3722                                 if(value != this._legendItemOrder)
3723                                 {
3724                                         this._legendItemOrder = value;
3725                                         this.Invalidate(false);
3726                                 }
3727                         }
3728                 }
3729
3730                 /// <summary>
3731                 /// Gets or sets a flag which indicates whether 
3732         /// legend rows should be drawn with interlaced background color.
3733                 /// </summary>
3734                 [
3735                 SRCategory("CategoryAttributeAppearance"),
3736                 DefaultValue(false),
3737                 SRDescription("DescriptionAttributeLegend_InterlacedRows"),
3738                 ]
3739                 public bool InterlacedRows
3740                 {
3741                         get
3742                         {
3743                                 return this._interlacedRows;
3744                         }
3745                         set
3746                         {
3747                                 if(value != this._interlacedRows)
3748                                 {
3749                                         this._interlacedRows = value;
3750                                         this.Invalidate(false);
3751                                 }
3752                         }
3753                 }
3754
3755                 /// <summary>
3756         /// Gets or sets the legend interlaced row's background color. Only applicable if interlaced rows are used. 
3757                 /// </summary>
3758                 [
3759                 SRCategory("CategoryAttributeAppearance"),
3760                 DefaultValue(typeof(Color), ""),
3761                 SRDescription("DescriptionAttributeLegend_InterlacedRowsColor"),
3762         TypeConverter(typeof(ColorConverter)),
3763         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3764                 ]
3765                 public Color InterlacedRowsColor
3766                 {
3767                         get
3768                         {
3769                                 return this._interlacedRowsColor;
3770                         }
3771                         set
3772                         {
3773                                 if(value != this._interlacedRowsColor)
3774                                 {
3775                                         this._interlacedRowsColor = value;
3776                                         this.Invalidate(false);
3777                                 }
3778                         }
3779                 }
3780
3781                 #endregion
3782
3783                 #region Legend Title Properties
3784
3785                 /// <summary>
3786                 /// Gets or sets the title text of the legend.
3787                 /// </summary>
3788                 [
3789                 SRCategory("CategoryAttributeTitle"),
3790                 DefaultValue(""),
3791                 SRDescription("DescriptionAttributeLegend_Title"),
3792                 ]
3793                 public string Title
3794                 {
3795                         get
3796                         {
3797                                 return this._title;
3798                         }
3799                         set
3800                         {
3801                                 if(value != this._title)
3802                                 {
3803                                         this._title = value;
3804                                         this.Invalidate(false);
3805                                 }
3806                         }
3807                 }
3808
3809                 /// <summary>
3810         /// Gets or sets the text color of the legend title.
3811                 /// </summary>
3812                 [
3813                 SRCategory("CategoryAttributeTitle"),
3814                 DefaultValue(typeof(Color), "Black"),
3815                 SRDescription("DescriptionAttributeLegend_TitleColor"),
3816         TypeConverter(typeof(ColorConverter)),
3817         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3818                 ]
3819                 public Color TitleForeColor
3820                 {
3821                         get
3822                         {
3823                                 return this._titleForeColor;
3824                         }
3825                         set
3826                         {
3827                                 if(value != this._titleForeColor)
3828                                 {
3829                                         this._titleForeColor = value;
3830                                         this.Invalidate(false);
3831                                 }
3832                         }
3833                 }
3834
3835                 /// <summary>
3836         /// Gets or sets the background color of the legend title. 
3837                 /// </summary>
3838                 [
3839                 SRCategory("CategoryAttributeTitle"),
3840                 DefaultValue(typeof(Color), ""),
3841         SRDescription("DescriptionAttributeTitleBackColor"),
3842         TypeConverter(typeof(ColorConverter)),
3843         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3844                 ]
3845                 public Color TitleBackColor
3846                 {
3847                         get
3848                         {
3849                                 return this._titleBackColor;
3850                         }
3851                         set
3852                         {
3853                                 if(value != this._titleBackColor)
3854                                 {
3855                                         this._titleBackColor = value;
3856                                         this.Invalidate(false);
3857                                 }
3858                         }
3859                 }
3860
3861                 /// <summary>
3862         /// Gets or sets the font of the legend title. 
3863                 /// </summary>
3864                 [
3865                 SRCategory("CategoryAttributeTitle"),
3866         DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt, style=Bold"),
3867         SRDescription("DescriptionAttributeTitleFont"),
3868                 ]
3869                 public Font TitleFont
3870                 {
3871                         get
3872                         {
3873                                 return this._titleFont;
3874                         }
3875                         set
3876                         {
3877                                 if(value != this._titleFont)
3878                                 {
3879                                         this._titleFont = value;
3880                                         this.Invalidate(false);
3881                                 }
3882                         }
3883                 }
3884
3885                 /// <summary>
3886         /// Gets or sets the text alignment of the legend title.
3887                 /// </summary>
3888                 [
3889                 SRCategory("CategoryAttributeTitle"),
3890                 DefaultValue(typeof(StringAlignment), "Center"),
3891                 SRDescription("DescriptionAttributeLegend_TitleAlignment"),
3892                 ]
3893                 public StringAlignment TitleAlignment
3894                 {
3895                         get
3896                         {
3897                                 return this._titleAlignment;
3898                         }
3899                         set
3900                         {
3901                                 if(value != this._titleAlignment)
3902                                 {
3903                                         this._titleAlignment = value;
3904                                         this.Invalidate(false);
3905                                 }
3906                         }
3907                 }
3908
3909                 /// <summary>
3910         /// Gets or sets the separator style of the legend title.
3911                 /// </summary>
3912                 [
3913                 SRCategory("CategoryAttributeTitle"),
3914                 DefaultValue(typeof(LegendSeparatorStyle), "None"),
3915                 SRDescription("DescriptionAttributeLegend_TitleSeparator"),
3916                 ]
3917                 public LegendSeparatorStyle TitleSeparator
3918                 {
3919                         get
3920                         {
3921                                 return this._titleSeparator;
3922                         }
3923                         set
3924                         {
3925                                 if(value != this._titleSeparator)
3926                                 {
3927                                         this._titleSeparator = value;
3928                                         this.Invalidate(false);
3929                                 }
3930                         }
3931                 }
3932
3933                 /// <summary>
3934         /// Gets or sets the separator color of the legend title.
3935                 /// </summary>
3936                 [
3937                 SRCategory("CategoryAttributeTitle"),
3938                 DefaultValue(typeof(Color), "Black"),
3939                 SRDescription("DescriptionAttributeLegend_TitleSeparatorColor"),
3940         TypeConverter(typeof(ColorConverter)),
3941         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
3942                 ]
3943                 public Color TitleSeparatorColor
3944                 {
3945                         get
3946                         {
3947                                 return this._titleSeparatorColor;
3948                         }
3949                         set
3950                         {
3951                                 if(value != this._titleSeparatorColor)
3952                                 {
3953                                         this._titleSeparatorColor = value;
3954                                         this.Invalidate(false);
3955                                 }
3956                         }
3957                 }
3958
3959
3960
3961                 #endregion // Legend Title Properties
3962
3963                 #region Legent Title and Header Helper methods
3964
3965                 /// <summary>
3966                 /// Gets legend title size in relative coordinates.
3967                 /// </summary>
3968                 /// <param name="chartGraph">Chart graphics.</param>
3969                 /// <param name="titleMaxSize">Maximum possible legend title size.</param>
3970                 /// <returns>Legend yitle size.</returns>
3971                 private Size GetTitleSize(ChartGraphics chartGraph, Size titleMaxSize)
3972                 {
3973                         Size titleSize = Size.Empty;
3974                         if(this.Title.Length > 0)
3975                         {
3976                                 // Adjust available space
3977                                 titleMaxSize.Width -= this.GetBorderSize() * 2 + this._offset.Width;
3978
3979                                 // Measure title text size
3980                                 titleSize = chartGraph.MeasureStringAbs(
3981                                         this.Title.Replace("\\n", "\n"), 
3982                                         this.TitleFont,
3983                                         titleMaxSize,
3984                                         StringFormat.GenericTypographic);
3985
3986                                 // Add text spacing
3987                                 titleSize.Height += this._offset.Height;
3988                                 titleSize.Width += this._offset.Width;
3989
3990                                 // Add space required for the title separator
3991                                 titleSize.Height += this.GetSeparatorSize(this.TitleSeparator).Height;
3992                         }
3993
3994                         return titleSize;
3995                 }
3996
3997                 /// <summary>
3998                 /// Gets legend header size in relative coordinates.
3999                 /// </summary>
4000                 /// <param name="chartGraph">Chart graphics.</param>
4001                 /// <param name="legendColumn">Legend column to get the header for.</param>
4002                 /// <returns>Legend yitle size.</returns>
4003                 private Size GetHeaderSize(ChartGraphics chartGraph, LegendCellColumn legendColumn)
4004                 {
4005                         Size headerSize = Size.Empty;
4006                         if(legendColumn.HeaderText.Length > 0)
4007                         {
4008                                 // Measure title text size
4009                                 headerSize = chartGraph.MeasureStringAbs(
4010                                         legendColumn.HeaderText.Replace("\\n", "\n") + "I", 
4011                                         legendColumn.HeaderFont);
4012
4013                                 // Add text spacing
4014                                 headerSize.Height += this._offset.Height;
4015                                 headerSize.Width += this._offset.Width;
4016
4017                                 // Add space required for the title separator
4018                                 headerSize.Height += this.GetSeparatorSize(this.HeaderSeparator).Height;
4019                         }
4020
4021                         return headerSize;
4022                 }
4023
4024                 /// <summary>
4025                 /// Draw Legend header.
4026                 /// </summary>
4027                 /// <param name="chartGraph">Chart graphics to draw the header on.</param>
4028                 private void DrawLegendHeader(ChartGraphics chartGraph)
4029                 {
4030                         // Check if header should be drawn
4031                         if(!this._headerPosition.IsEmpty &&
4032                                 this._headerPosition.Width > 0 &&
4033                                 this._headerPosition.Height > 0)
4034                         {
4035                                 int prevRightLocation = -1;
4036                                 bool redrawLegendBorder = false;
4037
4038                                 // Get Legend position
4039                                 Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
4040                                 legendPosition.Y += /*this.offset.Height + */this.GetBorderSize();
4041                                 legendPosition.Height -= 2 * (this._offset.Height + this.GetBorderSize());
4042                                 legendPosition.X += this.GetBorderSize();
4043                                 legendPosition.Width -= 2 * this.GetBorderSize();
4044                                 if(this.GetBorderSize() > 0)
4045                                 {
4046                                         ++legendPosition.Height;
4047                                         ++legendPosition.Width;
4048                                 }
4049
4050                                 // Check if at least 1 column header has non-empty background color
4051                                 bool    headerBackFill = false;
4052                                 for(int subColumnIndex = 0; subColumnIndex < this.CellColumns.Count; subColumnIndex++ )
4053                                 {
4054                                         LegendCellColumn legendColumn = this.CellColumns[subColumnIndex];
4055                                         if(!legendColumn.HeaderBackColor.IsEmpty)
4056                                         {
4057                                                 headerBackFill = true;
4058                                         }
4059                                 }
4060
4061                                 // Iterate through all columns
4062                                 for(int columnIndex = 0; columnIndex < this._itemColumns; columnIndex++ )
4063                                 {
4064                                         int columnStart = 0;
4065                                         int columnWidth = 0;
4066
4067                                         // Iterate through all sub-columns
4068                                         int numberOfSubColumns = this._subColumnSizes.GetLength(1);
4069                                         for(int subColumnIndex = 0; subColumnIndex < numberOfSubColumns; subColumnIndex++ )
4070                                         {
4071                                                 // Calculate position of the header
4072                                                 Rectangle rect = this._headerPosition;
4073                                                 if(_horizontalSpaceLeft > 0)
4074                                                 {
4075                                                         rect.X += (int)(this._horizontalSpaceLeft / 2f);
4076                                                 }
4077                                                 if(prevRightLocation != -1)
4078                                                 {
4079                                                         rect.X = prevRightLocation;
4080                                                 }
4081                                                 rect.Width = this._subColumnSizes[columnIndex, subColumnIndex];
4082                                                 prevRightLocation = rect.Right;
4083
4084                                                 // Remember column start position and update width
4085                                                 if(subColumnIndex == 0)
4086                                                 {
4087                                                         columnStart = rect.Left;
4088                                                 }
4089                                                 columnWidth += rect.Width;
4090
4091                                                 // Make sure header position do not go outside of the legend
4092                                                 rect.Intersect(legendPosition);
4093                                                 if(rect.Width > 0 && rect.Height > 0)
4094                                                 {
4095                                                         // Define fill rectangle
4096                                                         Rectangle fillRect = rect;
4097
4098                                                         // Make sure header fill riches legend top border
4099                                                         if(this._titlePosition.Height <= 0)
4100                                                         {
4101                                                                 fillRect.Y -= this._offset.Height;
4102                                                                 fillRect.Height += this._offset.Height;
4103                                                         }
4104
4105                                                         // Stretch header fill rectangle and separators when vertical 
4106                                                         // separator are used or if there is 1 column with header background
4107                                                         if( (this._itemColumns == 1 && headerBackFill) ||
4108                                                                 this.ItemColumnSeparator != LegendSeparatorStyle.None)
4109                                                         {
4110                                                                 // For the first cell in the first column stretch filling
4111                                                                 // to the left side of the legend
4112                                                                 if(columnIndex == 0 && subColumnIndex == 0)
4113                                                                 {
4114                                                                         int newX = legendPosition.X;
4115                                                                         columnWidth += columnStart - newX;
4116                                                                         columnStart = newX;
4117                                                                         fillRect.Width += fillRect.X - legendPosition.X;
4118                                                                         fillRect.X = newX;
4119                                                                 }
4120
4121                                                                 // For the last cell in the last column stretch filling
4122                                                                 // to the right side of the legend
4123                                                                 if(columnIndex == (this._itemColumns - 1) && 
4124                                                                         subColumnIndex == (numberOfSubColumns - 1) )
4125                                                                 {
4126                                                                         columnWidth += legendPosition.Right - fillRect.Right + 1;
4127                                                                         fillRect.Width += legendPosition.Right - fillRect.Right + 1;
4128                                                                 }
4129
4130                                                                 // For the first cell of any column except the first one
4131                                                                 // make sure we also fill the item column spacing
4132                                                                 if(columnIndex != 0 && subColumnIndex == 0)
4133                                                                 {
4134                                                                         columnWidth += this._itemColumnSpacingRel / 2;
4135                                                                         columnStart -= this._itemColumnSpacingRel / 2;
4136                                                                         fillRect.Width += this._itemColumnSpacingRel / 2;
4137                                                                         fillRect.X -= this._itemColumnSpacingRel / 2;
4138                                                                 }
4139
4140                                                                 // For the last cell in all columns except the last one 
4141                                                                 // make sure we also fill the item column spacing
4142                                                                 if(columnIndex != (this._itemColumns - 1) && 
4143                                                                         subColumnIndex == (numberOfSubColumns - 1) )
4144                                                                 {
4145                                                                         columnWidth += this._itemColumnSpacingRel / 2;
4146                                                                         fillRect.Width += this._itemColumnSpacingRel / 2;
4147                                                                 }
4148                                                         }
4149
4150                                                         if(subColumnIndex < this.CellColumns.Count)
4151                                                         {
4152                                                                 // Draw header background
4153                                                                 LegendCellColumn legendColumn = this.CellColumns[subColumnIndex];
4154                                                                 if(!legendColumn.HeaderBackColor.IsEmpty)
4155                                                                 {
4156                                                                         redrawLegendBorder = true;
4157
4158                                                                         // Fill title background
4159                                                                         if(fillRect.Right > legendPosition.Right)
4160                                                                         {
4161                                                                                 fillRect.Width -= (legendPosition.Right - fillRect.Right);
4162                                                                         }
4163                                                                         if(fillRect.X < legendPosition.X)
4164                                                                         {
4165                                                                                 fillRect.X += legendPosition.X - fillRect.X;
4166                                                                                 fillRect.Width -= (legendPosition.X - fillRect.X);
4167                                                                         }
4168                                                                         fillRect.Intersect(legendPosition);
4169                                                                         chartGraph.FillRectangleRel( 
4170                                                                                 chartGraph.GetRelativeRectangle(fillRect), 
4171                                                                                 legendColumn.HeaderBackColor, 
4172                                                                                 ChartHatchStyle.None,
4173                                                                                 string.Empty,
4174                                                                                 ChartImageWrapMode.Tile, 
4175                                                                                 Color.Empty,
4176                                                                                 ChartImageAlignmentStyle.Center,
4177                                                                                 GradientStyle.None, 
4178                                                                                 Color.Empty,
4179                                                                                 Color.Empty, 
4180                                                                                 0, 
4181                                                                                 ChartDashStyle.NotSet, 
4182                                                                                 Color.Empty, 
4183                                                                                 0,
4184                                                                                 PenAlignment.Inset);
4185
4186                                                                 }
4187
4188                                                                 // Draw header text
4189                                                                 using(SolidBrush textBrush = new SolidBrush(legendColumn.HeaderForeColor))
4190                                                                 {
4191                                                                         // Set text alignment
4192                                     using (StringFormat format = new StringFormat())
4193                                     {
4194                                         format.Alignment = legendColumn.HeaderAlignment;
4195                                         format.LineAlignment = StringAlignment.Center;
4196                                         format.FormatFlags = StringFormatFlags.LineLimit;
4197                                         format.Trimming = StringTrimming.EllipsisCharacter;
4198
4199                                         // Draw string using relative coordinates
4200                                         chartGraph.DrawStringRel(
4201                                             legendColumn.HeaderText,
4202                                             legendColumn.HeaderFont,
4203                                             textBrush,
4204                                             chartGraph.GetRelativeRectangle(rect),
4205                                             format);
4206                                     }
4207                                                                 }
4208                                                         }
4209                                                 }
4210                                         }
4211
4212                                         // Draw header separator for each column
4213                                         Rectangle separatorRect = this._headerPosition;
4214                                         separatorRect.X = columnStart;
4215                                         separatorRect.Width = columnWidth;
4216                                         if(this.HeaderSeparator == LegendSeparatorStyle.Line || this.HeaderSeparator == LegendSeparatorStyle.DoubleLine)
4217                                         {
4218                                                 // NOTE: For some reason a line with a single pen width is drawn 1 pixel longer than 
4219                                                 // any other line. Reduce width to solve the issue.
4220                                                 legendPosition.Width -= 1;
4221                                         }
4222                                         separatorRect.Intersect(legendPosition);
4223                                         this.DrawSeparator(chartGraph, this.HeaderSeparator, this.HeaderSeparatorColor, true, separatorRect);
4224
4225                                         // Add spacing between columns
4226                                         prevRightLocation += this.GetSeparatorSize(this.ItemColumnSeparator).Width;
4227                                 }
4228                         
4229                                 // Draw legend border to solve any issues with header background overlapping
4230                                 if(redrawLegendBorder)
4231                                 {
4232                                         chartGraph.FillRectangleRel( 
4233                                                 chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
4234                                                 Color.Transparent, 
4235                                                 ChartHatchStyle.None,
4236                                                 string.Empty,
4237                                                 ChartImageWrapMode.Tile, 
4238                                                 Color.Empty,
4239                                                 ChartImageAlignmentStyle.Center,
4240                                                 GradientStyle.None, 
4241                                                 Color.Empty,
4242                                                 BorderColor, 
4243                                                 this.GetBorderSize(), 
4244                                                 BorderDashStyle, 
4245                                                 Color.Empty, 
4246                                                 0,
4247                                                 PenAlignment.Inset);
4248
4249                                 }
4250                         
4251                                 // Add legend header hot region
4252                                 if( Common.ProcessModeRegions && !this._headerPosition.IsEmpty)
4253                                 {
4254                                         Common.HotRegionsList.AddHotRegion(chartGraph.GetRelativeRectangle(this._headerPosition), this, ChartElementType.LegendHeader, true );
4255                                 }
4256
4257                         }
4258                 }
4259
4260                 /// <summary>
4261                 /// Draw Legend title.
4262                 /// </summary>
4263                 /// <param name="chartGraph">Chart graphics to draw the title on.</param>
4264                 private void DrawLegendTitle(ChartGraphics chartGraph)
4265                 {
4266                         // Check if title text is specified and position recalculated
4267                         if(this.Title.Length > 0 &&
4268                                 !this._titlePosition.IsEmpty)
4269                         {
4270                                 // Get Legend position
4271                                 Rectangle legendPosition = Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()));
4272                                 legendPosition.Y += this.GetBorderSize();
4273                                 legendPosition.Height -= 2 * this.GetBorderSize();
4274                                 legendPosition.X += this.GetBorderSize();
4275                                 legendPosition.Width -= 2 * this.GetBorderSize();
4276                                 if(this.GetBorderSize() > 0)
4277                                 {
4278                                         ++legendPosition.Height;
4279                                         ++legendPosition.Width;
4280                                 }
4281
4282                                 // Draw title background
4283                                 if(!this.TitleBackColor.IsEmpty)
4284                                 {
4285                                         // Fill title background
4286                                         Rectangle fillRect = this._titlePosition;
4287                                         fillRect.Intersect(legendPosition);
4288                                         chartGraph.FillRectangleRel( 
4289                                                 chartGraph.GetRelativeRectangle(fillRect), 
4290                                                 this.TitleBackColor, 
4291                                                 ChartHatchStyle.None,
4292                                                 string.Empty,
4293                                                 ChartImageWrapMode.Tile, 
4294                                                 Color.Empty,
4295                                                 ChartImageAlignmentStyle.Center,
4296                                                 GradientStyle.None, 
4297                                                 Color.Empty,
4298                                                 Color.Empty, 
4299                                                 0, 
4300                                                 ChartDashStyle.NotSet, 
4301                                                 Color.Empty, 
4302                                                 0,
4303                                                 PenAlignment.Inset);
4304                                 }
4305
4306                                 // Draw title text
4307                                 using(SolidBrush textBrush = new SolidBrush(this.TitleForeColor))
4308                                 {
4309                                         // Set text alignment
4310                                         StringFormat format = new StringFormat();
4311                                         format.Alignment = this.TitleAlignment;
4312                                         //format.LineAlignment = StringAlignment.Center;
4313
4314                                         // Shift text rectangle by the top offset amount
4315                                         Rectangle rect = this._titlePosition;
4316                                         rect.Y += this._offset.Height;
4317                                         rect.X += this._offset.Width;
4318                                         rect.X += this.GetBorderSize();
4319                                         rect.Width -= this.GetBorderSize() * 2 + this._offset.Width;
4320
4321                                         // Draw string using relative coordinates
4322                                         rect.Intersect(legendPosition);
4323                                         chartGraph.DrawStringRel(
4324                                                 this.Title.Replace("\\n", "\n"),
4325                                                 this.TitleFont,
4326                                                 textBrush,
4327                                                 chartGraph.GetRelativeRectangle(rect),
4328                                                 format);
4329                                 }
4330
4331                                 // Draw title separator
4332                                 Rectangle separatorPosition = this._titlePosition;
4333                                 if(this.TitleSeparator == LegendSeparatorStyle.Line || this.TitleSeparator == LegendSeparatorStyle.DoubleLine)
4334                                 {
4335                                         // NOTE: For some reason a line with a single pen width is drawn 1 pixel longer than 
4336                                         // any other line. Reduce width to solve the issue.
4337                                         legendPosition.Width -= 1;
4338                                 }
4339                                 separatorPosition.Intersect(legendPosition);
4340                                 this.DrawSeparator(chartGraph, this.TitleSeparator, this.TitleSeparatorColor, true, separatorPosition);
4341
4342                                 // Draw legend border to solve any issues with title background overlapping
4343                                 if(!this.TitleBackColor.IsEmpty || 
4344                                         this.TitleSeparator != LegendSeparatorStyle.None)
4345                                 {
4346                                         chartGraph.FillRectangleRel( 
4347                                                 chartGraph.GetRelativeRectangle(Rectangle.Round(chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()))),
4348                                                 Color.Transparent, 
4349                                                 ChartHatchStyle.None,
4350                                                 string.Empty,
4351                                                 ChartImageWrapMode.Tile, 
4352                                                 Color.Empty,
4353                                                 ChartImageAlignmentStyle.Center,
4354                                                 GradientStyle.None, 
4355                                                 Color.Empty,
4356                                                 BorderColor, 
4357                                                 this.GetBorderSize(), 
4358                                                 BorderDashStyle, 
4359                                                 Color.Empty, 
4360                                                 0,
4361                                                 PenAlignment.Inset);
4362
4363                                 }
4364                         }
4365                 }
4366
4367                 /// <summary>
4368                 /// Gets legend separator size in pixels
4369                 /// </summary>
4370                 /// <param name="separatorType">Separator type.</param>
4371                 /// <returns>Separator size in relative coordinates.</returns>
4372                 internal Size GetSeparatorSize(LegendSeparatorStyle separatorType)
4373                 {
4374                         Size size = Size.Empty;
4375
4376                         if(separatorType == LegendSeparatorStyle.None)
4377                         {
4378                                 size = Size.Empty;
4379                         }
4380                         else if(separatorType == LegendSeparatorStyle.Line)
4381                         {
4382                                 size = new Size(1, 1);
4383                         }
4384                         else if(separatorType == LegendSeparatorStyle.DashLine)
4385                         {
4386                                 size = new Size(1, 1);
4387                         }
4388                         else if(separatorType == LegendSeparatorStyle.DotLine)
4389                         {
4390                                 size = new Size(1, 1);
4391                         }
4392                         else if(separatorType == LegendSeparatorStyle.ThickLine)
4393                         {
4394                                 size = new Size(2, 2);
4395                         }
4396                         else if(separatorType == LegendSeparatorStyle.DoubleLine)
4397                         {
4398                                 size = new Size(3, 3);
4399                         }
4400                         else if(separatorType == LegendSeparatorStyle.GradientLine)
4401                         {
4402                                 size = new Size(1, 1);
4403                         }
4404                         else if(separatorType == LegendSeparatorStyle.ThickGradientLine)
4405                         {
4406                                 size = new Size(2, 2);
4407                         }
4408                         else
4409                         {
4410                 throw (new InvalidOperationException(SR.ExceptionLegendSeparatorTypeUnknown(separatorType.ToString())));
4411                         }
4412
4413                         // For the vertical part of the separator always add additiobal spacing
4414                         size.Width += this._itemColumnSpacingRel;
4415
4416                         return size;
4417                 }
4418
4419                 /// <summary>
4420                 /// Draws specified legend separator.
4421                 /// </summary>
4422                 /// <param name="chartGraph">Chart graphics.</param>
4423                 /// <param name="separatorType">Separator type.</param>
4424                 /// <param name="color">Separator color.</param>
4425                 /// <param name="horizontal">Flag that determines if separator is vertical or horizontal.</param>
4426                 /// <param name="position">Separator position.</param>
4427                 private void DrawSeparator(
4428                         ChartGraphics chartGraph, 
4429                         LegendSeparatorStyle separatorType, 
4430                         Color color, 
4431                         bool horizontal,
4432                         Rectangle position)
4433                 {
4434                         // Temporary disable antialiasing
4435                         SmoothingMode oldSmoothingMode = chartGraph.SmoothingMode;
4436                         chartGraph.SmoothingMode = SmoothingMode.None;
4437
4438                         // Get line position in absolute coordinates
4439                         RectangleF rect = position;
4440                         if(!horizontal)
4441                         {
4442                                 rect.X += (int)(_itemColumnSpacingRel / 2f);
4443                                 rect.Width -= _itemColumnSpacingRel;
4444                         }
4445                         if(separatorType == LegendSeparatorStyle.Line)
4446                         {
4447                                 if(horizontal)
4448                                 {
4449                                         // Draw horizontal line separator
4450                                         chartGraph.DrawLineAbs(
4451                                                 color,
4452                                                 1,
4453                                                 ChartDashStyle.Solid,
4454                                                 new PointF(rect.Left, rect.Bottom - 1),
4455                                                 new PointF(rect.Right, rect.Bottom - 1) );
4456
4457                                 }
4458                                 else
4459                                 {
4460                                         // Draw vertical line separator
4461                                         chartGraph.DrawLineAbs(
4462                                                 color,
4463                                                 1,
4464                                                 ChartDashStyle.Solid,
4465                                                 new PointF(rect.Right - 1, rect.Top),
4466                                                 new PointF(rect.Right - 1, rect.Bottom) );
4467                                 }
4468                         }
4469                         else if(separatorType == LegendSeparatorStyle.DashLine)
4470                         {
4471                                 if(horizontal)
4472                                 {
4473                                         // Draw horizontal line separator
4474                                         chartGraph.DrawLineAbs(
4475                                                 color,
4476                                                 1,
4477                                                 ChartDashStyle.Dash,
4478                                                 new PointF(rect.Left, rect.Bottom - 1),
4479                                                 new PointF(rect.Right, rect.Bottom - 1) );
4480
4481                                 }
4482                                 else
4483                                 {
4484                                         // Draw vertical line separator
4485                                         chartGraph.DrawLineAbs(
4486                                                 color,
4487                                                 1,
4488                                                 ChartDashStyle.Dash,
4489                                                 new PointF(rect.Right - 1, rect.Top),
4490                                                 new PointF(rect.Right - 1, rect.Bottom) );
4491                                 }
4492                         }
4493                         else if(separatorType == LegendSeparatorStyle.DotLine)
4494                         {
4495                                 if(horizontal)
4496                                 {
4497                                         // Draw horizontal line separator
4498                                         chartGraph.DrawLineAbs(
4499                                                 color,
4500                                                 1,
4501                                                 ChartDashStyle.Dot,
4502                                                 new PointF(rect.Left, rect.Bottom - 1),
4503                                                 new PointF(rect.Right, rect.Bottom - 1) );
4504
4505                                 }
4506                                 else
4507                                 {
4508                                         // Draw vertical line separator
4509                                         chartGraph.DrawLineAbs(
4510                                                 color,
4511                                                 1,
4512                                                 ChartDashStyle.Dot,
4513                                                 new PointF(rect.Right - 1, rect.Top),
4514                                                 new PointF(rect.Right - 1, rect.Bottom) );
4515                                 }
4516                         }
4517                         else if(separatorType == LegendSeparatorStyle.ThickLine)
4518                         {
4519                                 if(horizontal)
4520                                 {
4521                                         // Draw horizontal line separator
4522                                         chartGraph.DrawLineAbs(
4523                                                 color,
4524                                                 2,
4525                                                 ChartDashStyle.Solid,
4526                                                 new PointF(rect.Left, rect.Bottom - 1f),
4527                                                 new PointF(rect.Right, rect.Bottom - 1f) );
4528                                 }
4529                                 else
4530                                 {
4531                                         // Draw vertical line separator
4532                                         chartGraph.DrawLineAbs(
4533                                                 color,
4534                                                 2,
4535                                                 ChartDashStyle.Solid,
4536                                                 new PointF(rect.Right - 1f, rect.Top),
4537                                                 new PointF(rect.Right - 1f, rect.Bottom) );
4538                                 }
4539                         }
4540                         else if(separatorType == LegendSeparatorStyle.DoubleLine)
4541                         {
4542                                 if(horizontal)
4543                                 {
4544                                         // Draw horizontal line separator
4545                                         chartGraph.DrawLineAbs(
4546                                                 color,
4547                                                 1,
4548                                                 ChartDashStyle.Solid,
4549                                                 new PointF(rect.Left, rect.Bottom - 3),
4550                                                 new PointF(rect.Right, rect.Bottom - 3) );
4551                                         chartGraph.DrawLineAbs(
4552                                                 color,
4553                                                 1,
4554                                                 ChartDashStyle.Solid,
4555                                                 new PointF(rect.Left, rect.Bottom - 1),
4556                                                 new PointF(rect.Right, rect.Bottom - 1) );
4557                                 }
4558                                 else
4559                                 {
4560                                         // Draw vertical line separator
4561                                         chartGraph.DrawLineAbs(
4562                                                 color,
4563                                                 1,
4564                                                 ChartDashStyle.Solid,
4565                                                 new PointF(rect.Right - 3, rect.Top),
4566                                                 new PointF(rect.Right - 3, rect.Bottom) );
4567                                         chartGraph.DrawLineAbs(
4568                                                 color,
4569                                                 1,
4570                                                 ChartDashStyle.Solid,
4571                                                 new PointF(rect.Right - 1, rect.Top),
4572                                                 new PointF(rect.Right - 1, rect.Bottom) );
4573                                 }
4574                         }
4575                         else if(separatorType == LegendSeparatorStyle.GradientLine)
4576                         {
4577                                 if(horizontal)
4578                                 {
4579                                         // Draw horizontal line separator
4580                                         chartGraph.FillRectangleAbs( 
4581                                                 new RectangleF(rect.Left, rect.Bottom - 1f, rect.Width, 0f), 
4582                                                 Color.Transparent, 
4583                                                 ChartHatchStyle.None,
4584                                                 string.Empty,
4585                                                 ChartImageWrapMode.Tile, 
4586                                                 Color.Empty,
4587                                                 ChartImageAlignmentStyle.Center,
4588                                                 GradientStyle.VerticalCenter, 
4589                                                 color,
4590                                                 Color.Empty, 
4591                                                 0, 
4592                                                 ChartDashStyle.NotSet, 
4593                                                 PenAlignment.Inset);
4594                                 }
4595                                 else
4596                                 {
4597                                         // Draw vertical line separator
4598                                         chartGraph.FillRectangleAbs( 
4599                                                 new RectangleF(rect.Right - 1f, rect.Top, 0f, rect.Height), 
4600                                                 Color.Transparent, 
4601                                                 ChartHatchStyle.None,
4602                                                 string.Empty,
4603                                                 ChartImageWrapMode.Tile, 
4604                                                 Color.Empty,
4605                                                 ChartImageAlignmentStyle.Center,
4606                                                 GradientStyle.HorizontalCenter, 
4607                                                 color,
4608                                                 Color.Empty, 
4609                                                 0, 
4610                                                 ChartDashStyle.NotSet, 
4611                                                 PenAlignment.Inset);
4612                                 }
4613                         }
4614                         else if(separatorType == LegendSeparatorStyle.ThickGradientLine)
4615                         {
4616                                 if(horizontal)
4617                                 {
4618                                         // Draw horizontal line separator
4619                                         chartGraph.FillRectangleAbs( 
4620                                                 new RectangleF(rect.Left, rect.Bottom - 2f, rect.Width, 1f), 
4621                                                 Color.Transparent, 
4622                                                 ChartHatchStyle.None,
4623                                                 string.Empty,
4624                                                 ChartImageWrapMode.Tile, 
4625                                                 Color.Empty,
4626                                                 ChartImageAlignmentStyle.Center,
4627                                                 GradientStyle.VerticalCenter, 
4628                                                 color,
4629                                                 Color.Empty, 
4630                                                 0, 
4631                                                 ChartDashStyle.NotSet, 
4632                                                 PenAlignment.Inset);
4633                                 }
4634                                 else
4635                                 {
4636                                         // Draw vertical line separator
4637                                         chartGraph.FillRectangleAbs( 
4638                                                 new RectangleF(rect.Right - 2f, rect.Top, 1f, rect.Height), 
4639                                                 Color.Transparent, 
4640                                                 ChartHatchStyle.None,
4641                                                 string.Empty,
4642                                                 ChartImageWrapMode.Tile, 
4643                                                 Color.Empty,
4644                                                 ChartImageAlignmentStyle.Center,
4645                                                 GradientStyle.HorizontalCenter, 
4646                                                 color,
4647                                                 Color.Empty, 
4648                                                 0, 
4649                                                 ChartDashStyle.NotSet, 
4650                                                 PenAlignment.Inset);
4651                                 }
4652                         }
4653
4654                         // Restore smoothing
4655                         chartGraph.SmoothingMode = oldSmoothingMode;
4656                 }
4657
4658                 #endregion // Legent Title Helper methods
4659
4660                 #region Helper methods
4661
4662                 /// <summary>
4663                 /// Get visible legend border size.
4664                 /// </summary>
4665                 /// <returns>Visible legend border size.</returns>
4666                 private int GetBorderSize()
4667                 {
4668                         if(this.BorderWidth > 0 &&
4669                                 this.BorderDashStyle != ChartDashStyle.NotSet &&
4670                                 !this.BorderColor.IsEmpty &&
4671                                 this.BorderColor != Color.Transparent)
4672                         {
4673                                 return this.BorderWidth;
4674                         }
4675                         return 0;
4676                 }
4677
4678                 /// <summary>
4679                 /// Helper method which returns current legend table style.
4680                 /// </summary>
4681                 /// <param name="chartGraph">Chart graphics.</param>
4682                 /// <returns>Legend table style.</returns>
4683                 private LegendTableStyle GetLegendTableStyle(ChartGraphics chartGraph)
4684                 {
4685                         LegendTableStyle style = this.TableStyle;
4686                         if(this.TableStyle == LegendTableStyle.Auto)
4687                         {
4688                                 if(this.Position.Auto)
4689                                 {
4690                                         // If legend is automatically positioned, use docking
4691                                         // do determine preffered table style
4692                                         if(this.Docking == Docking.Left ||
4693                                                 this.Docking == Docking.Right)
4694                                         {
4695                                                 return LegendTableStyle.Tall;
4696                                         }
4697                                         else
4698                                         {
4699                                                 return LegendTableStyle.Wide;
4700                                         }
4701                                 }
4702                                 else
4703                                 {
4704                                         // If legend is custom positioned, use legend width and heiht
4705                                         // to determine the best table layout.
4706                                         SizeF legendPixelSize = chartGraph.GetAbsoluteRectangle(this.Position.ToRectangleF()).Size;
4707                                         if(legendPixelSize.Width < legendPixelSize.Height)
4708                                         {
4709                                                 return LegendTableStyle.Tall;
4710                                         }
4711                                         else
4712                                         {
4713                                                 return LegendTableStyle.Wide;
4714                                         }
4715                                 }
4716                         }
4717                         
4718                         return style;
4719                 }
4720
4721
4722
4723                 /// <summary>
4724                 /// Helper method that checks if legend is enabled.
4725                 /// </summary>
4726                 /// <returns>True if legend is enabled.</returns>
4727                 internal bool IsEnabled()
4728                 {
4729                         if(this.Enabled)
4730                         {
4731
4732                                 // Check if legend is docked to the chart area
4733                                 if(this.DockedToChartArea.Length > 0 &&
4734                                         this.Common != null &&
4735                                         this.Common.ChartPicture != null)
4736                                 {
4737                                         if(this.Common.ChartPicture.ChartAreas.IndexOf(this.DockedToChartArea) >= 0)
4738                                         {
4739                                                 // Do not show legend when it is docked to invisible chart area
4740                                                 ChartArea area = this.Common.ChartPicture.ChartAreas[this.DockedToChartArea];
4741                                                 if(!area.Visible)
4742                                                 {
4743                                                         return false;
4744                                                 }
4745                                         }
4746                                 }
4747                                         
4748
4749                                 return true;
4750                         }
4751                         return false;
4752                 }
4753
4754                 /// <summary>
4755                 /// Invalidate chart legend when one of the properties is changed
4756                 /// </summary>
4757                 /// <param name="invalidateLegendOnly">Indicates that only legend area should be invalidated.</param>
4758         [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the Microsoft version of Chart")]
4759                 internal void Invalidate(bool invalidateLegendOnly)
4760                 {
4761 #if Microsoft_CONTROL
4762
4763                         if(Chart != null && !Chart.disableInvalidates)
4764                         {
4765                                 if(invalidateLegendOnly)
4766                                 {
4767                                         // Calculate the position of the legend
4768                                         Rectangle       invalRect = Chart.ClientRectangle;
4769                                         if(this.Position.Width != 0 && this.Position.Height != 0 )
4770                                         {
4771                                                 // Convert relative coordinates to absolute coordinates
4772                                                 invalRect.X = (int)(this.Position.X * (this.Common.ChartPicture.Width - 1) / 100F); 
4773                                                 invalRect.Y = (int)(this.Position.Y * (this.Common.ChartPicture.Height - 1) / 100F); 
4774                                                 invalRect.Width = (int)(this.Position.Width * (this.Common.ChartPicture.Width - 1) / 100F); 
4775                                                 invalRect.Height = (int)(this.Position.Height * (this.Common.ChartPicture.Height - 1) / 100F); 
4776
4777                                                 // Inflate rectangle size using border size and shadow size
4778                         invalRect.Inflate(this.BorderWidth + this.ShadowOffset + 1, this.BorderWidth + this.ShadowOffset + 1);
4779                                         }
4780
4781                                         // Invalidate legend rectangle only
4782                                         Chart.dirtyFlag = true;
4783                                         Chart.Invalidate(invalRect);
4784                                 }
4785                                 else
4786                                 {
4787                                         Invalidate();
4788                                 }
4789                         }
4790 #endif
4791                 }
4792
4793                 #endregion
4794
4795         #region IDisposable Members
4796
4797         /// <summary>
4798         /// Releases unmanaged and - optionally - managed resources
4799         /// </summary>
4800         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
4801         protected override void Dispose(bool disposing)
4802         {
4803             if (disposing)
4804             {
4805                 //Free managed resources
4806                 if (_fontCache != null)
4807                 {
4808                     _fontCache.Dispose();
4809                     _fontCache = null;
4810                 }
4811                 if (legendItems != null)
4812                 {
4813                     legendItems.Dispose();
4814                     legendItems = null;
4815                 }
4816                 if (_cellColumns != null)
4817                 {
4818                     _cellColumns.Dispose();
4819                     _cellColumns = null;
4820                 }
4821                 if (_customLegends != null)
4822                 {
4823                     _customLegends.Dispose();
4824                     _customLegends = null;
4825                 }
4826                 if (_position != null)
4827                 {
4828                     _position.Dispose();
4829                     _position = null;
4830                 }
4831             }
4832         }
4833
4834
4835         #endregion
4836     }
4837
4838         /// <summary>
4839     /// The LegendCollection class is a strongly typed collection of legends.
4840         /// </summary>
4841         [
4842                 SRDescription("DescriptionAttributeLegendCollection_LegendCollection"),
4843         ]
4844 #if ASPPERM_35
4845         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
4846     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
4847 #endif
4848     public class LegendCollection : ChartNamedElementCollection<Legend>
4849     {
4850         #region Constructors
4851                 /// <summary>
4852         /// LegendCollection constructor.
4853                 /// </summary>
4854         /// <param name="chartPicture">Chart picture object.</param>
4855         internal LegendCollection(ChartPicture chartPicture)
4856             : base(chartPicture)
4857         {
4858         }
4859
4860                 #endregion
4861
4862         #region Properties
4863         /// <summary>
4864         /// Gets the default legend name.
4865         /// </summary>
4866         internal string DefaultNameReference
4867         {
4868             get { return this.Count > 0 ? this[0].Name : String.Empty; }
4869         }
4870         #endregion
4871
4872                 #region Methods
4873
4874         /// <summary>
4875         /// Creates a new Legend with the specified name and adds it to the collection.
4876         /// </summary>
4877         /// <param name="name">The new chart area name.</param>
4878         /// <returns>New legend</returns>
4879         public Legend Add(string name)
4880         {
4881             Legend legend = new Legend(name);
4882             this.Add(legend);
4883             return legend;
4884         }
4885
4886         /// <summary>
4887                 /// Recalculates legend position in the collection.
4888                 /// </summary>
4889                 /// <param name="chartGraph">Chart graphics used.</param>
4890                 /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
4891                 /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
4892                 internal void CalcLegendPosition(
4893                         ChartGraphics chartGraph, 
4894                         ref RectangleF chartAreasRectangle, 
4895                         float elementSpacing)
4896                 {
4897                         // Loop through all legends
4898                         foreach(Legend legend in this)
4899                         {
4900                                 // Calculate position of the legends docked to the chart picture
4901                                 if(legend.IsEnabled() &&
4902                     legend.DockedToChartArea == Constants.NotSetValue && 
4903                                         legend.Position.Auto)
4904                                 {
4905                                         legend.CalcLegendPosition(chartGraph, ref chartAreasRectangle, elementSpacing);
4906                                 }
4907                         }
4908                 }
4909
4910                 /// <summary>
4911                 /// Recalculates legend position in the collection for legends docked outside of chart area.
4912                 /// </summary>
4913                 /// <param name="chartGraph">Chart graphics used.</param>
4914                 /// <param name="area">Area the legend is docked to.</param>
4915                 /// <param name="chartAreasRectangle">Area where the legend should be positioned.</param>
4916                 /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
4917                 internal void CalcOutsideLegendPosition(
4918                         ChartGraphics chartGraph, 
4919                         ChartArea area,
4920                         ref RectangleF chartAreasRectangle, 
4921                         float elementSpacing)
4922                 {
4923                         if(Common != null && Common.ChartPicture != null)
4924                         {
4925                                 // Get elemets spacing
4926                                 float areaSpacing = Math.Min((chartAreasRectangle.Height/100F) * elementSpacing, (chartAreasRectangle.Width/100F) * elementSpacing);
4927
4928                                 // Loop through all legends
4929                                 foreach(Legend legend in this)
4930                                 {
4931                                         // Check if all chart area names are valid
4932                     if (legend.DockedToChartArea != Constants.NotSetValue && this.Chart.ChartAreas.IndexOf(legend.DockedToChartArea)<0)
4933                     {
4934                         throw (new ArgumentException(SR.ExceptionLegendDockedChartAreaIsMissing((string)legend.DockedToChartArea)));
4935                     }
4936
4937                                         // Process only legends docked to specified area
4938                                         if(legend.IsEnabled() && 
4939                                                 legend.IsDockedInsideChartArea == false &&
4940                                                 legend.DockedToChartArea == area.Name && 
4941                                                 legend.Position.Auto)
4942                                         {
4943                                                 // Calculate legend position
4944                                                 legend.CalcLegendPosition(chartGraph, 
4945                                                         ref chartAreasRectangle,
4946                                                         areaSpacing);
4947
4948                                                 // Adjust legend position
4949                                                 RectangleF legendPosition = legend.Position.ToRectangleF();
4950                                                 if(legend.Docking == Docking.Top)
4951                                                 {
4952                                                         legendPosition.Y -= areaSpacing;
4953                                                         if(!area.Position.Auto)
4954                                                         {
4955                                                                 legendPosition.Y -= legendPosition.Height;
4956                                                         }
4957                                                 }
4958                                                 else if(legend.Docking == Docking.Bottom)
4959                                                 {
4960                                                         legendPosition.Y += areaSpacing;
4961                                                         if(!area.Position.Auto)
4962                                                         {
4963                                                                 legendPosition.Y = area.Position.Bottom + areaSpacing;
4964                                                         }
4965                                                 }
4966                                                 if(legend.Docking == Docking.Left)
4967                                                 {
4968                                                         legendPosition.X -= areaSpacing;
4969                                                         if(!area.Position.Auto)
4970                                                         {
4971                                                                 legendPosition.X -= legendPosition.Width;
4972                                                         }
4973                                                 }
4974                                                 if(legend.Docking == Docking.Right)
4975                                                 {
4976                                                         legendPosition.X += areaSpacing;
4977                                                         if(!area.Position.Auto)
4978                                                         {
4979                                                                 legendPosition.X = area.Position.Right + areaSpacing;
4980                                                         }
4981                                                 }
4982
4983                                                 legend.Position.SetPositionNoAuto(legendPosition.X, legendPosition.Y, legendPosition.Width, legendPosition.Height);
4984                                         }
4985                                 }
4986                         }
4987                 }
4988
4989                 /// <summary>
4990                 /// Recalculates legend position inside chart area in the collection.
4991                 /// </summary>
4992                 /// <param name="chartGraph">Chart graphics used.</param>
4993                 /// <param name="elementSpacing">Spacing size as a percentage of the area.</param>
4994                 internal void CalcInsideLegendPosition(
4995                         ChartGraphics chartGraph, 
4996                         float elementSpacing)
4997                 {
4998                         if(Common != null && Common.ChartPicture != null)
4999                         {
5000                                 // Check if all chart area names are valid
5001                                 foreach(Legend legend in this)
5002                                 {
5003                     if (legend.DockedToChartArea != Constants.NotSetValue)
5004                                         {
5005                                                 try
5006                                                 {
5007                                                         ChartArea area = Common.ChartPicture.ChartAreas[legend.DockedToChartArea];
5008                                                 }
5009                                                 catch
5010                                                 {
5011                                                         throw(new ArgumentException( SR.ExceptionLegendDockedChartAreaIsMissing( (string)legend.DockedToChartArea ) ) );
5012                                                 }
5013                                         }
5014                                 }
5015
5016                                 // Loop through all chart areas
5017                 foreach (ChartArea area in Common.ChartPicture.ChartAreas)
5018                                 {
5019
5020                                         // Check if chart area is visible
5021                                         if(area.Visible)
5022
5023                                         {
5024                                                 // Get area position
5025                                                 RectangleF legendPlottingRectangle = area.PlotAreaPosition.ToRectangleF();
5026
5027                                                 // Get elemets spacing
5028                                                 float areaSpacing = Math.Min((legendPlottingRectangle.Height/100F) * elementSpacing, (legendPlottingRectangle.Width/100F) * elementSpacing);
5029
5030                                                 // Loop through all legends
5031                                                 foreach(Legend legend in this)
5032                                                 {
5033                                                         if(legend.IsEnabled() && 
5034                                                                 legend.IsDockedInsideChartArea == true &&
5035                                                                 legend.DockedToChartArea == area.Name && 
5036                                                                 legend.Position.Auto)
5037                                                         {
5038                                                                 // Calculate legend position
5039                                                                 legend.CalcLegendPosition(chartGraph, 
5040                                                                         ref legendPlottingRectangle,
5041                                                                         areaSpacing);
5042                                                         }
5043                                                 }
5044                                         }
5045                                 }
5046                         }
5047                 }
5048
5049                 #endregion
5050
5051         #region Event handlers
5052         internal void ChartAreaNameReferenceChanged(object sender, NameReferenceChangedEventArgs e)
5053         {
5054             //If all the chart areas are removed and then the first one is added we don't want to dock the legends
5055             if (e.OldElement == null)
5056                 return;
5057
5058             foreach (Legend legend in this)
5059                 if (legend.DockedToChartArea == e.OldName)
5060                     legend.DockedToChartArea = e.NewName;
5061         }
5062         #endregion
5063
5064     }
5065
5066         /// <summary>
5067     /// The LegendItemsCollection class is a strongly typed collection of legend items.
5068         /// </summary>
5069         [
5070                 SRDescription("DescriptionAttributeCustomLabelsCollection_CustomLabelsCollection"),
5071         ]
5072 #if ASPPERM_35
5073         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
5074     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
5075 #endif
5076     public class LegendItemsCollection : ChartElementCollection<LegendItem>
5077         {
5078         #region Constructors
5079
5080         /// <summary>
5081         /// LegendItemsCollection constructor
5082                 /// </summary>
5083         internal LegendItemsCollection(Legend legend)
5084             : base(legend)
5085         {
5086         }
5087
5088                 #endregion
5089
5090                 #region Methods
5091
5092                 /// <summary>
5093                 /// Adds a legend item into the collection.
5094                 /// </summary>
5095                 /// <param name="color">Legend item color.</param>
5096                 /// <param name="text">Legend item text.</param>
5097                 /// <returns>Index of newly added item.</returns>
5098                 public int Add(Color color, string text)
5099                 {
5100                         LegendItem      item = new LegendItem(text, color, "");
5101                         Add(item);
5102             return Count - 1;
5103                 }
5104
5105                 /// <summary>
5106                 /// Insert a legend item into the collection.
5107                 /// </summary>
5108                 /// <param name="index">Index to insert at.</param>
5109                 /// <param name="color">Legend item color.</param>
5110                 /// <param name="text">Legend item text.</param>
5111                 /// <returns>Index of newly added item.</returns>
5112                 public void Insert(int index, Color color, string text)
5113                 {
5114                         LegendItem      item = new LegendItem(text, color, "");
5115                         this.Insert(index, item);
5116                 }
5117
5118                 /// <summary>
5119                 /// Adds a legend item into the collection.
5120                 /// </summary>
5121                 /// <param name="image">Legend item image.</param>
5122                 /// <param name="text">Legend item text.</param>
5123                 /// <returns>Index of newly added item.</returns>
5124                 public int Add(string image, string text)
5125                 {
5126                         LegendItem      item = new LegendItem(text, Color.Empty, image);
5127             Add(item);
5128                         return Count-1;
5129                 }
5130
5131                 /// <summary>
5132                 /// Insert one legend item into the collection.
5133                 /// </summary>
5134                 /// <param name="index">Index to insert at.</param>
5135                 /// <param name="image">Legend item image.</param>
5136                 /// <param name="text">Legend item text.</param>
5137                 /// <returns>Index of newly added item.</returns>
5138                 public void Insert(int index, string image, string text)
5139                 {
5140                         LegendItem      item = new LegendItem(text, Color.Empty, image);
5141                         this.Insert(index, item);
5142                 }
5143
5144                 /// <summary>
5145                 /// Reverses the order of items in the collection.
5146                 /// </summary>
5147                 public void Reverse()
5148                 {
5149             List<LegendItem> list = this.Items as List<LegendItem>;
5150             list.Reverse();
5151                         Invalidate();
5152                 }
5153
5154                 #endregion
5155
5156         }
5157
5158
5159         /// <summary>
5160     /// The LegendItem class represents a single item (row) in the legend.
5161     /// It contains properties which describe visual appearance and
5162     /// content of the legend item.
5163         /// </summary>
5164         [
5165         SRDescription("DescriptionAttributeLegendItem_LegendItem"),
5166         DefaultProperty("Name"),
5167         ]
5168 #if Microsoft_CONTROL
5169         public class LegendItem : ChartNamedElement
5170 #else
5171 #if ASPPERM_35
5172         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
5173     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
5174 #endif
5175     public class LegendItem : ChartNamedElement, IChartMapArea
5176 #endif
5177     {
5178         #region Fields
5179
5180         // Private data members, which store properties values
5181                 private Color                                   _color = Color.Empty;
5182                 private string                                  _image = "";
5183                 private string                                  _seriesName = "";
5184                 private int                                             _seriesPointIndex = -1;
5185
5186                 // Chart image map properties 
5187                 private string                                  _toolTip = "";
5188         
5189 #if !Microsoft_CONTROL
5190                 private string                                  _url = "";
5191                 private string                                  _attributes = "";
5192         private string                  _postbackValue = String.Empty;
5193 #endif
5194
5195         // Additional appearance properties
5196                 internal LegendImageStyle               style = LegendImageStyle.Rectangle;
5197                 internal GradientStyle                  backGradientStyle = GradientStyle.None;
5198                 internal Color                                  backSecondaryColor = Color.Empty;
5199                 internal Color                                  backImageTransparentColor = Color.Empty;
5200                 internal Color                                  borderColor = Color.Black;
5201                 internal int                                    borderWidth = 1;
5202                 internal ChartDashStyle                 borderDashStyle = ChartDashStyle.Solid;
5203                 internal ChartHatchStyle                backHatchStyle = ChartHatchStyle.None;
5204                 internal int                                    shadowOffset = 0;
5205                 internal Color                                  shadowColor = Color.FromArgb(128, 0, 0, 0);
5206                 internal ChartImageWrapMode             backImageWrapMode = ChartImageWrapMode.Tile;
5207                 internal ChartImageAlignmentStyle               backImageAlign = ChartImageAlignmentStyle.TopLeft;
5208
5209                 // Marker properties
5210                 internal MarkerStyle                    markerStyle = MarkerStyle.None;
5211                 internal int                                    markerSize = 5;
5212                 internal string                                 markerImage = "";
5213                 internal Color                                  markerImageTransparentColor = Color.Empty;
5214                 internal Color                                  markerColor = Color.Empty;
5215                 internal Color                                  markerBorderColor = Color.Empty;
5216
5217                 // True if legend item is enabled.
5218                 private bool            _enabled = true;
5219
5220                 // Series marker border width
5221                 private int                     _markerBorderWidth = 1;
5222
5223                 // Collection of legend item cells
5224                 private LegendCellCollection    _cells = null;
5225
5226                 // Legend item visual separator
5227                 private LegendSeparatorStyle    _separatorType = LegendSeparatorStyle.None;
5228
5229                 // Legend item visual separator color
5230                 private Color           _separatorColor = Color.Black;
5231
5232                 // Indicates that temporary cells where added and thet have to be removed
5233                 internal bool           clearTempCells = false;
5234
5235                 #endregion
5236
5237                 #region Constructors
5238
5239                 /// <summary>
5240         /// LegendItem constructor
5241                 /// </summary>
5242                 public LegendItem()
5243                 {
5244
5245                         // Create collection of legend item cells
5246                         this._cells = new LegendCellCollection(this);
5247 #if !Microsoft_CONTROL
5248             this.PostBackValue = String.Empty;
5249 #endif //!WIN_CONTROL
5250                 }
5251
5252                 /// <summary>
5253         /// LegendItem constructor
5254                 /// </summary>
5255                 /// <param name="name">Item name.</param>
5256                 /// <param name="color">Item color.</param>
5257                 /// <param name="image">Item image.</param>
5258                 public LegendItem(string name, Color color, string image) : base (name)
5259                 {
5260                         this._color = color;
5261                         this._image = image;
5262
5263                         // Create collection of legend item cells
5264                         this._cells = new LegendCellCollection(this);
5265 #if !Microsoft_CONTROL
5266             this.PostBackValue = String.Empty;
5267 #endif //!WIN_CONTROL
5268                 }
5269
5270                 #endregion
5271
5272                 #region Legend item properties
5273
5274         /// <summary>
5275         /// Gets the Legend object which the item belongs to.
5276         /// </summary>
5277         [
5278             Bindable(false),
5279             Browsable(false),
5280             DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
5281             SerializationVisibilityAttribute(SerializationVisibility.Hidden),
5282         ]
5283         public Legend Legend
5284         {
5285             get 
5286             {
5287                 if (Parent != null)
5288                     return Parent.Parent as Legend;
5289                 else
5290                     return null;
5291             }
5292         }
5293
5294                 /// <summary>
5295                 /// Gets or sets the name of the legend item.
5296                 /// </summary>
5297                 [
5298                 SRCategory("CategoryAttributeAppearance"),
5299                 Bindable(true),
5300                 SRDescription("DescriptionAttributeLegendItem_Name"),
5301                 NotifyParentPropertyAttribute(true),
5302                 #if !Microsoft_CONTROL
5303                 PersistenceMode(PersistenceMode.Attribute),
5304                 #endif
5305                 ParenthesizePropertyNameAttribute(true)
5306                 ]
5307                 public override string Name
5308                 {
5309                         get
5310                         {
5311                                 return base.Name;
5312                         }
5313                         set
5314                         {
5315                                 base.Name = value;
5316                         }
5317                 }
5318
5319                 /// <summary>
5320                 /// Gets or sets the color of the legend item.
5321                 /// </summary>
5322                 [
5323                 SRCategory("CategoryAttributeAppearance"),
5324                 Bindable(true),
5325                 SRDescription("DescriptionAttributeLegendItem_Color"),
5326                 DefaultValue(typeof(Color), ""),
5327                 NotifyParentPropertyAttribute(true),
5328         TypeConverter(typeof(ColorConverter)),
5329         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5330                 #if !Microsoft_CONTROL
5331                 PersistenceMode(PersistenceMode.Attribute)
5332                 #endif
5333                 ]
5334                 public  Color Color
5335                 {
5336                         get
5337                         {
5338                                 return _color;
5339                         }
5340                         set
5341                         {
5342                                 _color = value;
5343                                 this.Invalidate(true);
5344                         }
5345                 }
5346
5347                 /// <summary>
5348         /// Gets or sets a string value that represents a URL to an image file, which will be used for the legend item's symbol.
5349                 /// </summary>
5350                 [
5351                 SRCategory("CategoryAttributeAppearance"),
5352                 Bindable(true),
5353                 SRDescription("DescriptionAttributeLegendItem_Image"),
5354                 DefaultValue(""),
5355         Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
5356                 #if !Microsoft_CONTROL
5357                 PersistenceMode(PersistenceMode.Attribute),
5358                 #endif
5359                 NotifyParentPropertyAttribute(true)
5360                 ]
5361                 public  string Image
5362                 {
5363                         get
5364                         {
5365                                 return _image;
5366                         }
5367                         set
5368                         {
5369                                 _image = value;
5370                                 this.Invalidate(false);
5371                         }
5372                 }
5373
5374                 /// <summary>
5375                 /// Gets or sets the picture style of the legend item image.
5376                 /// </summary>
5377                 [
5378                 SRCategory("CategoryAttributeAppearance"),
5379                 Bindable(true),
5380                 DefaultValue(typeof(LegendImageStyle), "Rectangle"),
5381                 SRDescription("DescriptionAttributeLegendItem_Style"),
5382                 #if !Microsoft_CONTROL
5383                 PersistenceMode(PersistenceMode.Attribute),
5384                 #endif
5385                 ParenthesizePropertyNameAttribute(true)
5386                 ]
5387                 public LegendImageStyle ImageStyle
5388                 {
5389                         get
5390                         {
5391                                 return style;
5392                         }
5393                         set
5394                         {
5395                                 style = value;
5396                                 this.Invalidate(true);
5397                         }
5398                 }
5399
5400
5401                 /// <summary>
5402                 /// Gets or sets the border color of the legend item.
5403                 /// </summary>
5404                 [
5405                 SRCategory("CategoryAttributeAppearance"),
5406                 Bindable(true),
5407                 DefaultValue(typeof(Color), "Black"),
5408         SRDescription("DescriptionAttributeBorderColor"),
5409         TypeConverter(typeof(ColorConverter)),
5410         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5411                 #if !Microsoft_CONTROL
5412                 PersistenceMode(PersistenceMode.Attribute)
5413                 #endif
5414                 ]
5415                 public Color BorderColor
5416                 {
5417                         get
5418                         {
5419                                 return borderColor;
5420                         }
5421                         set
5422                         {
5423                                 borderColor = value;
5424                                 this.Invalidate(true);
5425                         }
5426                 }
5427
5428                 /// <summary>
5429         /// Gets or sets the background hatch style of the legend item.
5430                 /// </summary>
5431                 [
5432                 SRCategory("CategoryAttributeAppearance"),
5433                 Bindable(true),
5434                 DefaultValue(ChartHatchStyle.None),
5435         SRDescription("DescriptionAttributeBackHatchStyle"),
5436                 #if !Microsoft_CONTROL
5437                 PersistenceMode(PersistenceMode.Attribute),
5438                 #endif
5439         Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
5440                 ]
5441                 public ChartHatchStyle BackHatchStyle
5442                 {
5443                         get
5444                         {
5445                                 return backHatchStyle;
5446                         }
5447                         set
5448                         {
5449                                 backHatchStyle = value;
5450                                 this.Invalidate(true);
5451                         }
5452                 }
5453
5454                 /// <summary>
5455         /// Gets or sets a color which will be replaced with a transparent color while drawing the background image.
5456                 /// </summary>
5457                 [
5458                 SRCategory("CategoryAttributeAppearance"),
5459                 Bindable(true),
5460                 DefaultValue(typeof(Color), ""),
5461                 NotifyParentPropertyAttribute(true),
5462         SRDescription("DescriptionAttributeImageTransparentColor"),
5463         TypeConverter(typeof(ColorConverter)),
5464         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5465                 #if !Microsoft_CONTROL
5466                 PersistenceMode(PersistenceMode.Attribute)
5467                 #endif
5468                 ]
5469                 public Color BackImageTransparentColor
5470                 {
5471                         get
5472                         {
5473                                 return backImageTransparentColor;
5474                         }
5475                         set
5476                         {
5477                                 backImageTransparentColor = value;
5478                                 this.Invalidate(true);
5479                         }
5480                 }
5481
5482         /// <summary>
5483         /// Gets or sets background gradient style of the legend item.
5484         /// </summary>
5485                 [
5486                 SRCategory("CategoryAttributeAppearance"),
5487                 Bindable(true),
5488                 DefaultValue(GradientStyle.None),
5489         SRDescription("DescriptionAttributeBackGradientStyle"),
5490                 #if !Microsoft_CONTROL
5491                 PersistenceMode(PersistenceMode.Attribute),
5492                 #endif
5493         Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
5494                 ]
5495                 public GradientStyle BackGradientStyle
5496                 {
5497                         get
5498                         {
5499                                 return backGradientStyle;
5500                         }
5501                         set
5502                         {
5503                                 backGradientStyle = value;
5504                                 this.Invalidate(true);
5505                         }
5506                 }
5507
5508         /// <summary>
5509         /// Gets or sets the secondary background color.
5510         /// <seealso cref="Color"/>
5511         /// <seealso cref="BackHatchStyle"/>
5512         /// <seealso cref="BackGradientStyle"/>
5513         /// </summary>
5514         /// <value>
5515         /// A <see cref="Color"/> value used for the secondary color of background with 
5516         /// hatching or gradient fill.
5517         /// </value>
5518         /// <remarks>
5519         /// This color is used with <see cref="Color"/> when <see cref="BackHatchStyle"/> or
5520         /// <see cref="BackGradientStyle"/> are used.
5521         /// </remarks>
5522                 [
5523                 SRCategory("CategoryAttributeAppearance"),
5524                 Bindable(true),
5525                 DefaultValue(typeof(Color), ""),
5526         SRDescription("DescriptionAttributeBackSecondaryColor"),
5527         TypeConverter(typeof(ColorConverter)),
5528         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5529                 #if !Microsoft_CONTROL
5530                 PersistenceMode(PersistenceMode.Attribute)
5531                 #endif
5532                 ]
5533                 public Color BackSecondaryColor
5534                 {
5535                         get
5536                         {
5537                                 return backSecondaryColor;
5538                         }
5539                         set
5540                         {
5541                                 if(value != Color.Empty && (value.A != 255 || value == Color.Transparent))
5542                                 {
5543                     throw (new ArgumentException(SR.ExceptionBackSecondaryColorIsTransparent));
5544                                 }
5545
5546                                 backSecondaryColor = value;
5547
5548                                 this.Invalidate(true);
5549                         }
5550                 }
5551
5552                 /// <summary>
5553                 /// Gets or sets the border width of the legend item.
5554                 /// </summary>
5555                 [
5556                 SRCategory("CategoryAttributeAppearance"),
5557                 Bindable(true),
5558                 DefaultValue(1),
5559         SRDescription("DescriptionAttributeBorderWidth"),
5560                 #if !Microsoft_CONTROL
5561                 PersistenceMode(PersistenceMode.Attribute)
5562                 #endif
5563                 ]
5564                 public int BorderWidth
5565                 {
5566                         get
5567                         {
5568                                 return borderWidth;
5569                         }
5570                         set
5571                         {
5572                                 if(value < 0)
5573                                 {
5574                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionBorderWidthIsZero));
5575                                 }
5576                                 borderWidth = value;
5577                                 this.Invalidate(false);
5578                         }
5579                 }
5580
5581
5582
5583         /// <summary>
5584         /// Gets or sets a flag which indicates whether the Legend item is enabled.
5585         /// </summary>
5586                 [
5587                 SRCategory("CategoryAttributeAppearance"),
5588                 DefaultValue(true),
5589                 SRDescription("DescriptionAttributeLegendItem_Enabled"),
5590                 ParenthesizePropertyNameAttribute(true),
5591                 ]
5592                 public bool Enabled
5593                 {
5594                         get
5595                         {
5596                                 return this._enabled;
5597                         }
5598                         set
5599                         {
5600                                 this._enabled = value;
5601                                 this.Invalidate(false);
5602                         }
5603                 }
5604
5605                 /// <summary>
5606                 /// Gets or sets the marker border width of the legend item.
5607                 /// </summary>
5608                 [
5609                 SRCategory("CategoryAttributeMarker"),
5610                 DefaultValue(1),
5611         SRDescription("DescriptionAttributeMarkerBorderWidth"),
5612                 #if !Microsoft_CONTROL
5613                 PersistenceMode(PersistenceMode.Attribute)
5614                 #endif
5615                 ]
5616                 public int MarkerBorderWidth
5617                 {
5618                         get
5619                         {
5620                                 return this._markerBorderWidth;
5621                         }
5622                         set
5623                         {
5624                                 if(value < 0)
5625                                 {
5626                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionLegendMarkerBorderWidthIsNegative));
5627                                 }
5628                                 this._markerBorderWidth = value;
5629                                 this.Invalidate(false);
5630                         }
5631                 }
5632
5633
5634
5635         /// <summary>
5636         /// Gets or sets the legend item border style.
5637         /// </summary>
5638                 [
5639                 SRCategory("CategoryAttributeAppearance"),
5640                 Bindable(true),
5641                 DefaultValue(ChartDashStyle.Solid),
5642         SRDescription("DescriptionAttributeBorderDashStyle"),
5643                 #if !Microsoft_CONTROL
5644                 PersistenceMode(PersistenceMode.Attribute)
5645                 #endif
5646                 ]
5647                 public ChartDashStyle BorderDashStyle
5648                 {
5649                         get
5650                         {
5651                                 return borderDashStyle;
5652                         }
5653                         set
5654                         {
5655                                 borderDashStyle = value;
5656                                 this.Invalidate(true);
5657                         }
5658                 }
5659
5660         /// <summary>
5661         /// Gets or sets the offset between the legend item and its shadow.
5662         /// <seealso cref="ShadowColor"/>
5663         /// </summary>
5664         /// <value>
5665         /// An integer value that represents the offset between the legend item and its shadow.
5666         /// </value>
5667                 [
5668                 SRCategory("CategoryAttributeAppearance"),
5669                 Bindable(true),
5670         SRDescription("DescriptionAttributeShadowOffset"),
5671 #if !Microsoft_CONTROL
5672                 PersistenceMode(PersistenceMode.InnerProperty),
5673 #endif
5674                 DefaultValue(0)
5675                 ]
5676                 public int ShadowOffset
5677                 {
5678                         get
5679                         {
5680                                 return shadowOffset;
5681                         }
5682                         set
5683                         {
5684                                 shadowOffset = value;
5685                                 this.Invalidate(false);
5686                         }
5687                 }
5688
5689         /// <summary>
5690         /// Gets or sets the color of a legend item's shadow.
5691         /// <seealso cref="ShadowOffset"/>
5692         /// </summary>
5693         /// <value>
5694         /// A <see cref="Color"/> value used to draw a legend item's shadow.
5695         /// </value>
5696                 [
5697                 SRCategory("CategoryAttributeAppearance"),
5698                 Bindable(true),
5699                 DefaultValue(typeof(Color), "128,0,0,0"),
5700         SRDescription("DescriptionAttributeShadowColor"),
5701         TypeConverter(typeof(ColorConverter)),
5702         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5703                 #if !Microsoft_CONTROL
5704                 PersistenceMode(PersistenceMode.Attribute)
5705                 #endif
5706                 ]
5707                 public Color ShadowColor
5708                 {
5709                         get
5710                         {
5711                                 return shadowColor;
5712                         }
5713                         set
5714                         {
5715                                 shadowColor = value;
5716                                 this.Invalidate(true);
5717                         }
5718                 }
5719
5720                 /// <summary>
5721                 /// Gets or sets the marker style of the legend item.
5722                 /// </summary>
5723                 [
5724                 SRCategory("CategoryAttributeMarker"),
5725                 Bindable(true),
5726                 DefaultValue(MarkerStyle.None),
5727                 SRDescription("DescriptionAttributeLegendItem_MarkerStyle"),
5728                 #if !Microsoft_CONTROL
5729                 PersistenceMode(PersistenceMode.Attribute),
5730                 #endif
5731         Editor(Editors.MarkerStyleEditor.Editor, Editors.MarkerStyleEditor.Base),
5732                 RefreshProperties(RefreshProperties.All)
5733                 ]
5734                 public MarkerStyle MarkerStyle
5735                 {
5736                         get
5737                         {
5738                                 return markerStyle;
5739                         }
5740                         set
5741                         {
5742                                 markerStyle = value;
5743                                 this.Invalidate(true);
5744                         }
5745                 }
5746
5747                 /// <summary>
5748         /// Gets or sets the marker size of the legend item.
5749                 /// </summary>
5750                 [
5751                 SRCategory("CategoryAttributeMarker"),
5752                 Bindable(true),
5753                 DefaultValue(5),
5754                 SRDescription("DescriptionAttributeLegendItem_MarkerSize"),
5755                 #if !Microsoft_CONTROL
5756                 PersistenceMode(PersistenceMode.Attribute),
5757                 #endif
5758                 RefreshProperties(RefreshProperties.All)
5759                 ]
5760                 public int MarkerSize
5761                 {
5762                         get
5763                         {
5764                                 return markerSize;
5765                         }
5766                         set
5767                         {
5768                                 markerSize = value;
5769                                 this.Invalidate(false);
5770                         }
5771                 }
5772
5773                 /// <summary>
5774         /// Gets or sets the marker image of the legend item.
5775                 /// </summary>
5776                 [
5777                 SRCategory("CategoryAttributeMarker"),
5778                 Bindable(true),
5779                 DefaultValue(""),
5780         SRDescription("DescriptionAttributeMarkerImage"),
5781         Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
5782                 #if !Microsoft_CONTROL
5783                 PersistenceMode(PersistenceMode.Attribute),
5784                 #endif
5785                 RefreshProperties(RefreshProperties.All)
5786                 ]
5787                 public string MarkerImage
5788                 {
5789                         get
5790                         {
5791                                 return markerImage;
5792                         }
5793                         set
5794                         {
5795                                 markerImage = value;
5796                                 this.Invalidate(true);
5797                         }
5798                 }
5799
5800                 /// <summary>
5801         /// Gets or sets a color which will be replaced with a transparent color while drawing the marker image.
5802                 /// </summary>
5803                 [
5804                 SRCategory("CategoryAttributeMarker"),
5805                 Bindable(true),
5806                 DefaultValue(typeof(Color), ""),
5807         SRDescription("DescriptionAttributeImageTransparentColor"),
5808         TypeConverter(typeof(ColorConverter)),
5809         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5810                 #if !Microsoft_CONTROL
5811                 PersistenceMode(PersistenceMode.Attribute),
5812                 #endif
5813                 RefreshProperties(RefreshProperties.All)
5814                 ]
5815                 public Color MarkerImageTransparentColor
5816                 {
5817                         get
5818                         {
5819                                 return markerImageTransparentColor;
5820                         }
5821                         set
5822                         {
5823                                 markerImageTransparentColor = value;
5824                                 this.Invalidate(true);
5825                         }
5826                 }
5827                 
5828                 /// <summary>
5829         /// Gets or sets the marker color of the legend item.
5830                 /// </summary>
5831                 [
5832                 SRCategory("CategoryAttributeMarker"),
5833                 Bindable(true),
5834                 DefaultValue(typeof(Color), ""),
5835                 SRDescription("DescriptionAttributeLegendItem_MarkerColor"),
5836         TypeConverter(typeof(ColorConverter)),
5837         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5838                 #if !Microsoft_CONTROL
5839                 PersistenceMode(PersistenceMode.Attribute),
5840                 #endif
5841                 RefreshProperties(RefreshProperties.All)
5842                 ]
5843                 public Color MarkerColor
5844                 {
5845                         get
5846                         {
5847                                 return markerColor;
5848                         }
5849                         set
5850                         {
5851                                 markerColor = value;
5852                                 this.Invalidate(true);
5853                         }
5854                 }
5855                 
5856                 /// <summary>
5857         /// Gets or sets the marker border color of the legend item.
5858                 /// </summary>
5859                 [
5860                 SRCategory("CategoryAttributeMarker"),
5861                 Bindable(true),
5862                 DefaultValue(typeof(Color), ""),
5863         SRDescription("DescriptionAttributeMarkerBorderColor"),
5864         TypeConverter(typeof(ColorConverter)),
5865         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5866                 #if !Microsoft_CONTROL
5867                 PersistenceMode(PersistenceMode.Attribute),
5868                 #endif
5869                 RefreshProperties(RefreshProperties.All)
5870                 ]
5871                 public Color MarkerBorderColor
5872                 {
5873                         get
5874                         {
5875                                 return markerBorderColor;
5876                         }
5877                         set
5878                         {
5879                                 markerBorderColor = value;
5880                                 this.Invalidate(true);
5881                         }
5882                 }
5883
5884
5885                 /// <summary>
5886         /// Gets or sets the series name of the legend item..
5887                 /// </summary>
5888                 [
5889                 Browsable(false),
5890         DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
5891         SerializationVisibilityAttribute(SerializationVisibility.Hidden),
5892         SRDescription("DescriptionAttributeLegendItem_SeriesName"),
5893                 DefaultValue("")
5894                 ]
5895                 public  string SeriesName
5896                 {
5897                         get
5898                         {
5899                                 return _seriesName;
5900                         }
5901                         set
5902                         {
5903                                 _seriesName = value;
5904                         }
5905                 }
5906
5907                 /// <summary>
5908         /// Gets or sets the index of the legend item's associated DataPoint object.
5909                 /// </summary>
5910                 [
5911                 Browsable(false),
5912         DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
5913         SerializationVisibilityAttribute(SerializationVisibility.Hidden),
5914         SRDescription("DescriptionAttributeLegendItem_SeriesPointIndex"),
5915                 DefaultValue(-1)
5916                 ]
5917                 public  int SeriesPointIndex
5918                 {
5919                         get
5920                         {
5921                                 return _seriesPointIndex;
5922                         }
5923                         set
5924                         {
5925                                 _seriesPointIndex = value;
5926                         }
5927                 }
5928
5929
5930
5931
5932                 /// <summary>
5933                 /// Gets or sets the separator style of the legend item.
5934                 /// </summary>
5935                 [
5936                 SRCategory("CategoryAttributeAppearance"),
5937                 DefaultValue(typeof(LegendSeparatorStyle), "None"),
5938                 SRDescription("DescriptionAttributeLegendItem_Separator"),
5939                 ]
5940                 public LegendSeparatorStyle SeparatorType
5941                 {
5942                         get
5943                         {
5944                                 return this._separatorType;
5945                         }
5946                         set
5947                         {
5948                                 if(value != this._separatorType)
5949                                 {
5950                                         this._separatorType = value;
5951                                         this.Invalidate(false);
5952                                 }
5953                         }
5954                 }
5955
5956                 /// <summary>
5957         /// Gets or sets the separator color of the legend item.
5958                 /// </summary>
5959                 [
5960                 SRCategory("CategoryAttributeAppearance"),
5961                 DefaultValue(typeof(Color), "Black"),
5962                 SRDescription("DescriptionAttributeLegendItem_SeparatorColor"),
5963         TypeConverter(typeof(ColorConverter)),
5964         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
5965                 ]
5966                 public Color SeparatorColor
5967                 {
5968                         get
5969                         {
5970                                 return this._separatorColor;
5971                         }
5972                         set
5973                         {
5974                                 if(value != this._separatorColor)
5975                                 {
5976                                         this._separatorColor = value;
5977                                         this.Invalidate(false);
5978                                 }
5979                         }
5980                 }
5981
5982
5983                 /// <summary>
5984         /// The LegendCellCollection class is a collection of legend item cells.
5985                 /// </summary>
5986                 [
5987                 SRCategory("CategoryAttributeAppearance"),
5988                 SRDescription("DescriptionAttributeLegendItem_Cells"),
5989 #if Microsoft_CONTROL
5990                 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
5991 #else
5992                 PersistenceMode(PersistenceMode.InnerProperty),
5993 #endif
5994         Editor(Editors.LegendCellCollectionEditor.Editor, Editors.LegendCellCollectionEditor.Base),
5995                 ]
5996                 public LegendCellCollection Cells
5997                 {
5998                         get
5999                         {
6000                                 return this._cells;
6001                         }
6002                 }
6003
6004                 #endregion
6005
6006                 #region IMapAreaAttributesutes Properties implementation
6007
6008                 /// <summary>
6009                 /// Tooltip of the area.
6010                 /// </summary>
6011                 [
6012                 SRCategory("CategoryAttributeMapArea"),
6013         Bindable(true),
6014         SRDescription("DescriptionAttributeToolTip"),
6015                 DefaultValue(""),
6016                 #if !Microsoft_CONTROL
6017                 PersistenceMode(PersistenceMode.Attribute)
6018                 #endif
6019                 ]
6020                 public string ToolTip
6021                 {
6022                         set
6023                         {
6024                                 _toolTip = value;
6025 #if Microsoft_CONTROL
6026                                 if(Chart != null && Chart.selection != null)
6027                                 {
6028                                         Chart.selection.enabledChecked = false;
6029                                 }
6030 #endif
6031
6032                         }
6033                         get
6034                         {
6035                                 return _toolTip;
6036                         }
6037                 }
6038
6039 #if !Microsoft_CONTROL
6040                 /// <summary>
6041                 /// URL target of the area.
6042                 /// </summary>
6043                 [
6044                 SRCategory("CategoryAttributeMapArea"),
6045                 Bindable(true),
6046                 SRDescription("DescriptionAttributeUrl"),
6047                 DefaultValue(""),
6048 #if !Microsoft_CONTROL
6049                 PersistenceMode(PersistenceMode.Attribute),
6050         Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base)
6051 #endif
6052                 ]
6053                 public string Url
6054                 {
6055                         set
6056                         {
6057                                 _url = value;
6058                         }
6059                         get
6060                         {
6061                                 return _url;
6062                         }
6063                 }
6064
6065 #endif
6066 #if !Microsoft_CONTROL
6067
6068                 /// <summary>
6069                 /// Other attributes of the area.
6070                 /// </summary>
6071                 [
6072                 SRCategory("CategoryAttributeMapArea"),
6073                 Bindable(true),
6074                 SRDescription("DescriptionAttributeMapAreaAttributes"),
6075                 DefaultValue(""),
6076                 PersistenceMode(PersistenceMode.Attribute)
6077                 ]
6078                 public string MapAreaAttributes
6079                 {
6080                         set
6081                         {
6082                                 _attributes = value;
6083                         }
6084                         get
6085                         {
6086                                 return _attributes;
6087                         }
6088                 }
6089         /// <summary>
6090         /// Gets or sets the postback value which can be processed on a click event.
6091         /// </summary>
6092         /// <value>The value which is passed to a click event as an argument.</value>
6093         [DefaultValue("")]
6094         [SRCategory(SR.Keys.CategoryAttributeMapArea)]
6095         [SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
6096         public string PostBackValue 
6097         {
6098             get
6099             {
6100                 return this._postbackValue;
6101             }
6102             set
6103             {
6104                 this._postbackValue = value;
6105             } 
6106         }
6107
6108
6109 #endif //!Microsoft_CONTROL
6110         #endregion
6111
6112         #region Helper methods
6113
6114         /// <summary>
6115                 /// Helper method adds default legend item cells based on the columns
6116                 /// specified. If columns collection is empty we assume the presence of
6117                 /// two columns: series marker and legend item text.
6118                 /// </summary>
6119                 /// <param name="legend">Legend this item belongs to.</param>
6120                 internal void AddAutomaticCells(Legend legend)
6121                 {
6122                         // Check if cells defined
6123                         if(this.Cells.Count == 0)
6124                         {
6125                                 // Check if legend item was generated for the series
6126                                 if(this.SeriesName.Length > 0)
6127                                 {
6128                                         // If legend do not have any columns set add a series marker
6129                                         // and legend text cells
6130                                         if(legend.CellColumns.Count == 0)
6131                                         {
6132                         // VSTS 96787 - Text Direction (RTL/LTR)        
6133                         if (legend.Common != null && legend.Common.ChartPicture.RightToLeft == RightToLeft.Yes)
6134                         {
6135                             this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
6136                             this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
6137                         }
6138                         else
6139                         {
6140                             this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
6141                             this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
6142                         }
6143                                         }
6144                                         else
6145                                         {
6146                                                 // Add cell for each of the columns
6147                                                 foreach(LegendCellColumn legendColumn in legend.CellColumns)
6148                                                 {
6149                                                         this.Cells.Add(legendColumn.CreateNewCell());
6150                                                 }
6151                                         }
6152                                 }
6153                                 else
6154                                 {
6155                                         // Add Marker plus text for everything else
6156                                         this.clearTempCells = true;
6157                                         this.Cells.Add(LegendCellType.SeriesSymbol, string.Empty, ContentAlignment.MiddleCenter);
6158                                         this.Cells.Add(LegendCellType.Text, KeywordName.LegendText, ContentAlignment.MiddleLeft);
6159                                 }
6160                         }
6161                 }
6162
6163
6164                 /// <summary>
6165                 /// Sets legend item properties from the series
6166                 /// </summary>
6167                 /// <param name="series">Series object.</param>
6168                 /// <param name="common">Common elements object.</param>
6169                 internal void SetAttributes(CommonElements common, Series series)
6170                 {
6171                         // Get legend item picture style
6172                         IChartType chartType = common.ChartTypeRegistry.GetChartType(series.ChartTypeName);
6173                         style = chartType.GetLegendImageStyle(series);
6174
6175                         // Set series name
6176                         _seriesName = series.Name;
6177
6178                         // Get shadow properties
6179                         shadowOffset = series.ShadowOffset;
6180                         shadowColor = series.ShadowColor;
6181
6182                         // Check if series is drawn in 3D chart area
6183                         bool area3D = common.Chart.ChartAreas[series.ChartArea].Area3DStyle.Enable3D;
6184
6185                         // Get other properties
6186                         SetAttributes((DataPointCustomProperties) series, area3D);
6187                 }
6188
6189                 /// <summary>
6190                 /// Sets legend item properties from the DataPointCustomProperties object.
6191                 /// </summary>
6192         /// <param name="properties">DataPointCustomProperties object.</param>
6193                 /// <param name="area3D">Element belongs to the 3D area.</param>
6194         internal void SetAttributes(DataPointCustomProperties properties, bool area3D)
6195                 {
6196                         borderColor = properties.BorderColor;
6197                         borderWidth = properties.BorderWidth;
6198                         borderDashStyle = properties.BorderDashStyle;
6199                         markerStyle = properties.MarkerStyle;
6200                         markerSize = properties.MarkerSize;
6201                         markerImage = properties.MarkerImage;
6202                         markerImageTransparentColor = properties.MarkerImageTransparentColor;
6203                         markerColor = properties.MarkerColor;
6204                         markerBorderColor = properties.MarkerBorderColor;
6205
6206
6207                         this._markerBorderWidth = properties.MarkerBorderWidth;
6208             
6209             float dpi = 96;
6210
6211             if(Common != null)
6212                 dpi = Common.graph.Graphics.DpiX;
6213             
6214             int maxBorderWidth = (int)Math.Round((2 * dpi) / 96);
6215
6216             if (this._markerBorderWidth > maxBorderWidth)
6217                         {
6218                 this._markerBorderWidth = maxBorderWidth;
6219                         }
6220
6221                         if(properties.MarkerBorderWidth <= 0)
6222                         {
6223                                 markerBorderColor = Color.Transparent;
6224                         }
6225
6226                         // Improve readability of the line series marker by using at least 2 pixel wide lines
6227                         if(this.style == LegendImageStyle.Line &&
6228                 borderWidth <= (int)Math.Round(dpi / 96) )
6229                         {
6230                 borderWidth = maxBorderWidth;
6231                         }
6232
6233                         if(!area3D)
6234                         {
6235                                 backGradientStyle = properties.BackGradientStyle;
6236                                 backSecondaryColor = properties.BackSecondaryColor;
6237                                 backImageTransparentColor = properties.BackImageTransparentColor;
6238                                 backImageWrapMode = properties.BackImageWrapMode;
6239                                 backImageAlign = properties.BackImageAlignment;
6240                                 backHatchStyle = properties.BackHatchStyle;
6241                         }
6242                 }
6243
6244                 /// <summary>
6245                 /// Invalidate chart (or just legend )when collection is changed
6246                 /// </summary>
6247         [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This parameter is used when compiling for the Microsoft version of Chart")]
6248                 private void Invalidate(bool invalidateLegendOnly)
6249                 {
6250 #if Microsoft_CONTROL
6251                         if(Legend != null)
6252                         {
6253                                 // Invalidate control
6254                                 Legend.Invalidate(invalidateLegendOnly);
6255                         }
6256 #endif
6257                 }
6258
6259                 #endregion
6260
6261         #region IDisposable Members
6262
6263         /// <summary>
6264         /// Releases unmanaged and - optionally - managed resources
6265         /// </summary>
6266         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
6267         protected override void Dispose(bool disposing)
6268         {
6269             if (disposing)
6270             {
6271                 if (_cells != null)
6272                 {
6273                     _cells.Dispose();
6274                     _cells = null;
6275                 }
6276             }
6277             base.Dispose(disposing);
6278         }
6279
6280
6281         #endregion
6282
6283         }
6284 }