ImageList.cs: Use upper case initials for internal fields. ImageStream: Create handle...
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ImageList.cs
1 //
2 // System.Windows.Forms.ImageList.cs
3 //
4 // Authors:
5 //   Peter Bartok <pbartok@novell.com>
6 //   Kornél Pál <http://www.kornelpal.hu/>
7 //
8 // Copyright (C) 2004-2005 Novell, Inc.
9 // Copyright (C) 2005 Kornél Pál
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 // COMPLETE
34
35 //
36 // Differences between MS.NET ImageList and this implementation:
37 //
38 // This is a fully managed image list implementation.
39 //
40 // Images are stored as Format32bppArgb internally but ColorDepth is applied
41 // to the colors of images. Images[index] returns a Format32bppArgb copy of
42 // the image so this difference is only internal.
43 //
44 // MS.NET has no alpha channel support (except for icons in 32-bit mode with
45 // comctl32.dll version 6.0) but this implementation has full alpha channel
46 // support in 32-bit mode.
47 //
48 // Handle should be an HIMAGELIST returned by ImageList_Create. This
49 // implementation uses (IntPtr)(-1) that is a non-zero but invalid handle.
50 //
51 // MS.NET creates handle when images are accessed. Add methods are caching the
52 // original images without modification. This implementation adds images in
53 // Add methods so handle is created in Add methods.
54 //
55 // MS.NET 1.x shares the same HIMAGELIST between ImageLists that were
56 // initialized from the same ImageListStreamer and doesn't update ImageSize
57 // and ColorDepth that are treated as bugs.
58 //
59
60 using System.Collections;
61 using System.ComponentModel;
62 using System.Drawing;
63 using System.Drawing.Imaging;
64 using System.Runtime.InteropServices;
65
66 namespace System.Windows.Forms
67 {
68         [DefaultProperty("Images")]
69         [Designer("System.Windows.Forms.Design.ImageListDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
70         [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
71         [TypeConverter("System.Windows.Forms.ImageListConverter, " + Consts.AssemblySystem_Windows_Forms)]
72         public sealed class ImageList : System.ComponentModel.Component
73         {
74                 #region Private Fields
75                 private EventHandler recreateHandle;
76                 private readonly ImageCollection images;
77                 #endregion // Private Fields
78
79                 #region Sub-classes
80                 [Editor("System.Windows.Forms.Design.ImageCollectionEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
81                 public sealed class ImageCollection : IList, ICollection, IEnumerable
82                 {
83                         private const int AlphaMask = unchecked((int)0xFF000000);
84
85                         [StructLayout(LayoutKind.Explicit)]
86                         private struct ArgbColor
87                         {
88                                 [FieldOffset(0)]
89                                 internal int Argb;
90                                 [FieldOffset(0)]
91                                 internal byte Blue;
92                                 [FieldOffset(1)]
93                                 internal byte Green;
94                                 [FieldOffset(2)]
95                                 internal byte Red;
96                                 [FieldOffset(3)]
97                                 internal byte Alpha;
98                         }
99
100                         private
101 #if NET_2_0
102                         static
103 #else
104                         sealed
105 #endif
106                         class IndexedColorDepths
107                         {
108 #if !NET_2_0
109                                 private IndexedColorDepths()
110                                 {
111                                 }
112 #endif
113                                 internal static readonly ArgbColor[] Palette4Bit;
114                                 internal static readonly ArgbColor[] Palette8Bit;
115                                 private static readonly int[] squares;
116
117                                 static IndexedColorDepths()
118                                 {
119                                         Color[] palette;
120                                         Bitmap bitmap;
121                                         int index;
122                                         int count;
123
124                                         bitmap = new Bitmap(1, 1, PixelFormat.Format4bppIndexed);
125                                         palette = bitmap.Palette.Entries;
126                                         bitmap.Dispose();
127
128                                         Palette4Bit = new ArgbColor[count = palette.Length];
129                                         for (index = 0; index < count; index++)
130                                                 Palette4Bit[index].Argb = palette[index].ToArgb();
131
132                                         bitmap = new Bitmap(1, 1, PixelFormat.Format8bppIndexed);
133                                         palette = bitmap.Palette.Entries;
134                                         bitmap.Dispose();
135
136                                         Palette8Bit = new ArgbColor[count = palette.Length];
137                                         for (index = 0; index < count; index++)
138                                                 Palette8Bit[index].Argb = palette[index].ToArgb();
139
140                                         squares = new int[511];
141                                         for (index = 0; index < 256; index++)
142                                                 squares[255 + index] = squares[255 - index] = index * index;
143                                 }
144
145                                 internal static int GetNearestColor(ArgbColor[] palette, int color)
146                                 {
147                                         int index;
148                                         int count;
149                                         int red;
150                                         int green;
151                                         int blue;
152                                         int nearestColor;
153                                         int minDistance;
154                                         int distance;
155
156                                         count = palette.Length;
157                                         for (index = 0; index < count; index++)
158                                                 if (palette[index].Argb == color)
159                                                         return color;
160
161                                         red = unchecked((int)(unchecked((uint)color) >> 16) & 0xFF);
162                                         green = unchecked((int)(unchecked((uint)color) >> 8) & 0xFF);
163                                         blue = color & 0xFF;
164                                         nearestColor = AlphaMask;
165                                         minDistance = int.MaxValue;
166
167                                         for (index = 0; index < count; index++)
168                                                 if ((distance = squares[255 + palette[index].Red - red] + squares[255 + palette[index].Green - green] + squares[255 + palette[index].Blue - blue]) < minDistance) {
169                                                         nearestColor = palette[index].Argb;
170                                                         minDistance = distance;
171                                                 }
172
173                                         return nearestColor;
174                                 }
175
176                         }
177
178                         #region ImageCollection Private Fields
179                         private ColorDepth colorDepth = ColorDepth.Depth8Bit;
180                         private Color transparentColor = Color.Transparent;
181                         private Size imageSize = new Size(16, 16);
182                         private bool handleCreated;
183                         private readonly ArrayList list = new ArrayList();
184                         private readonly ImageList owner;
185                         #endregion // ImageCollection Private Fields
186
187                         #region ImageCollection Internal Constructors
188                         // For use in ImageList
189                         internal ImageCollection(ImageList owner)
190                         {
191                                 this.owner = owner;
192                         }
193                         #endregion // ImageCollection Internal Constructor
194
195                         #region ImageCollection Internal Instance Properties
196                         // For use in ImageList
197                         internal ColorDepth ColorDepth {
198                                 get {
199                                         return this.colorDepth;
200                                 }
201
202                                 set {
203                                         if (!Enum.IsDefined(typeof(ColorDepth), value))
204                                                 throw new InvalidEnumArgumentException("value", (int)value, typeof(ColorDepth));
205
206                                         if (this.colorDepth != value) {
207                                                 this.colorDepth = value;
208                                                 if (handleCreated) {
209                                                         list.Clear();
210                                                         owner.OnRecreateHandle();
211                                                 }
212                                         }
213                                 }
214                         }
215
216                         // For use in ImageList
217                         internal IntPtr Handle {
218                                 get {
219                                         this.handleCreated = true;
220                                         return (IntPtr)(-1);
221                                 }
222                         }
223
224                         // For use in ImageList
225                         internal bool HandleCreated {
226                                 get {
227                                         return this.handleCreated;
228                                 }
229                         }
230
231                         // For use in ImageList
232                         internal Size ImageSize {
233                                 get {
234                                         return this.imageSize;
235                                 }
236
237                                 set {
238                                         if (value.Width < 1 || value.Width > 256 || value.Height < 1 || value.Height > 256)
239                                                 throw new ArgumentException("ImageSize.Width and Height must be between 1 and 256", "value");
240
241                                         if (this.imageSize != value) {
242                                                 this.imageSize = value;
243                                                 if (handleCreated) {
244                                                         list.Clear();
245                                                         owner.OnRecreateHandle();
246                                                 }
247                                         }
248                                 }
249                         }
250
251                         // For use in ImageList
252                         internal ImageListStreamer ImageStream {
253                                 get {
254                                         return list.Count == 0 ? null : new ImageListStreamer(this);
255                                 }
256
257                                 set {
258                                         int index;
259                                         Image[] streamImages;
260
261                                         if (value == null) {
262 #if NET_2_0
263                                                 this.handleCreated = false;
264                                                 list.Clear();
265 #endif
266                                         }
267                                         else if ((streamImages = value.Images) != null) {
268                                                 this.handleCreated = true;
269                                                 list.Clear();
270
271                                                 for (index = 0; index < streamImages.Length; index++)
272                                                         list.Add((Image)streamImages[index].Clone());
273
274                                                 this.imageSize = value.ImageSize;
275                                                 this.colorDepth = value.ColorDepth;
276 #if NET_2_0
277                                                 // Event is raised even when handle was not created yet.
278                                                 owner.OnRecreateHandle();
279 #endif
280                                         }
281                                 }
282                         }
283
284                         // For use in ImageList
285                         internal Color TransparentColor {
286                                 get {
287                                         return this.transparentColor;
288                                 }
289
290                                 set {
291                                         this.transparentColor = value;
292                                 }
293                         }
294                         #endregion // ImageCollection Internal Instance Properties
295
296                         #region ImageCollection Public Instance Properties
297                         [Browsable(false)]
298                         public int Count {
299                                 get {
300                                         return list.Count;
301                                 }
302                         }
303
304                         public bool Empty {
305                                 get {
306                                         return list.Count == 0;
307                                 }
308                         }
309
310                         public bool IsReadOnly {
311                                 get {
312                                         return false;
313                                 }
314                         }
315
316                         [Browsable(false)]
317                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
318                         public Image this[int index] {
319                                 get {
320                                         return (Image)GetImage(index).Clone();
321                                 }
322
323                                 set {
324                                         if (index < 0 || index >= list.Count)
325                                                 throw new ArgumentOutOfRangeException("index");
326
327                                         list[index] = CreateImage(value, this.transparentColor);
328                                 }
329                         }
330                         #endregion // ImageCollection Public Instance Properties
331
332                         #region ImageCollection Private Instance Methods
333                         private Image CreateImage(Image value, Color transparentColor)
334                         {
335                                 int width;
336                                 int height;
337                                 Bitmap bitmap;
338                                 Graphics graphics;
339                                 ImageAttributes imageAttributes;
340
341                                 if (value == null)
342                                         throw new ArgumentNullException("value");
343
344                                 if (!(value is Bitmap))
345                                         throw new ArgumentException("Image must be a Bitmap.");
346
347                                 if (transparentColor.A == 0)
348                                         imageAttributes = null;
349                                 else {
350                                         imageAttributes = new ImageAttributes();
351                                         imageAttributes.SetColorKey(transparentColor, transparentColor);
352                                 }
353
354                                 bitmap = new Bitmap(width = this.imageSize.Width, height = this.imageSize.Height, PixelFormat.Format32bppArgb);
355                                 graphics = Graphics.FromImage(bitmap);
356                                 graphics.DrawImage(value, new Rectangle(0, 0, width, height), 0, 0, value.Width, value.Height, GraphicsUnit.Pixel, imageAttributes);
357                                 graphics.Dispose();
358
359                                 return ReduceColorDepth(bitmap);
360                         }
361
362                         private unsafe Image ReduceColorDepth(Bitmap bitmap)
363                         {
364                                 byte* pixelPtr;
365                                 byte* lineEndPtr;
366                                 byte* linePtr;
367                                 int line;
368                                 int pixel;
369                                 int height;
370                                 int widthBytes;
371                                 int stride;
372                                 BitmapData bitmapData;
373                                 ArgbColor[] palette;
374
375                                 if (this.colorDepth < ColorDepth.Depth32Bit) {
376                                         bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
377                                         try {
378                                                 linePtr = (byte*)bitmapData.Scan0;
379                                                 height = bitmapData.Height;
380                                                 widthBytes = bitmapData.Width << 2;
381                                                 stride = bitmapData.Stride;
382
383                                                 if (this.colorDepth < ColorDepth.Depth16Bit) {
384                                                         palette = this.colorDepth < ColorDepth.Depth8Bit ? IndexedColorDepths.Palette4Bit : IndexedColorDepths.Palette8Bit;
385
386                                                         for (line = 0; line < height; line++) {
387                                                                 lineEndPtr = linePtr + widthBytes;
388                                                                 for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
389                                                                         *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : IndexedColorDepths.GetNearestColor(palette, pixel | AlphaMask);
390                                                                 linePtr += stride;
391                                                         }
392                                                 }
393                                                 else if (this.colorDepth < ColorDepth.Depth24Bit) {
394                                                         for (line = 0; line < height; line++) {
395                                                                 lineEndPtr = linePtr + widthBytes;
396                                                                 for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
397                                                                         *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : (pixel & 0x00F8F8F8) | AlphaMask;
398                                                                 linePtr += stride;
399                                                         }
400                                                 }
401                                                 else {
402                                                         for (line = 0; line < height; line++) {
403                                                                 lineEndPtr = linePtr + widthBytes;
404                                                                 for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
405                                                                         *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : pixel | AlphaMask;
406                                                                 linePtr += stride;
407                                                         }
408                                                 }
409                                         }
410                                         finally {
411                                                 bitmap.UnlockBits(bitmapData);
412                                         }
413                                 }
414
415                                 return bitmap;
416                         }
417                         #endregion // ImageCollection Private Instance Methods
418
419                         #region ImageCollection Internal Instance Methods
420                         // For use in ImageList
421                         internal Image GetImage(int index)
422                         {
423                                 if (index < 0 || index >= list.Count)
424                                         throw new ArgumentOutOfRangeException("index");
425
426                                 return (Image)list[index];
427                         }
428
429                         // For use in ImageListStreamer
430                         internal Image[] ToArray()
431                         {
432                                 Image[] images = new Image[list.Count];
433
434                                 list.CopyTo(images);
435                                 return images;
436                         }
437                         #endregion // ImageCollection Internal Instance Methods
438
439                         #region ImageCollection Public Instance Methods
440                         public void Add(Icon value)
441                         {
442                                 int width;
443                                 int height;
444                                 Bitmap bitmap;
445                                 Graphics graphics;
446
447                                 if (value == null)
448                                         throw new ArgumentNullException("value");
449
450                                 this.handleCreated = true;
451
452                                 bitmap = new Bitmap(width = this.imageSize.Width, height = this.imageSize.Height, PixelFormat.Format32bppArgb);
453                                 graphics = Graphics.FromImage(bitmap);
454                                 graphics.DrawIcon(value, new Rectangle(0, 0, width, height));
455                                 graphics.Dispose();
456
457                                 list.Add(ReduceColorDepth(bitmap));
458                         }
459
460                         public void Add(Image value)
461                         {
462                                 Add(value, this.transparentColor);
463                         }
464
465                         public int Add(Image value, Color transparentColor)
466                         {
467                                 this.handleCreated = true;
468                                 return list.Add(CreateImage(value, transparentColor));
469                         }
470
471                         public int AddStrip(Image value)
472                         {
473                                 int imageX;
474                                 int imageWidth;
475                                 int width;
476                                 int height;
477                                 int index;
478                                 Bitmap bitmap;
479                                 Graphics graphics;
480                                 Rectangle imageRect;
481                                 ImageAttributes imageAttributes;
482
483                                 if (value == null)
484                                         throw new ArgumentNullException("value");
485
486                                 if ((imageWidth = value.Width) == 0 || (imageWidth % (width = this.imageSize.Width)) != 0)
487                                         throw new ArgumentException("Width of image strip must be a positive multiple of ImageSize.Width.", "value");
488
489                                 if (value.Height != (height = this.imageSize.Height))
490                                         throw new ArgumentException("Height of image strip must be equal to ImageSize.Height.", "value");
491
492                                 if (!(value is Bitmap))
493                                         throw new ArgumentException("Image must be a Bitmap.");
494
495                                 this.handleCreated = true;
496
497                                 imageRect = new Rectangle(0, 0, width, height);
498                                 if (this.transparentColor.A == 0)
499                                         imageAttributes = null;
500                                 else {
501                                         imageAttributes = new ImageAttributes();
502                                         imageAttributes.SetColorKey(this.transparentColor, this.transparentColor);
503                                 }
504
505                                 index = list.Count;
506                                 for (imageX = 0; imageX < imageWidth; imageX += width) {
507                                         bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
508                                         graphics = Graphics.FromImage(bitmap);
509                                         graphics.DrawImage(value, imageRect, imageX, 0, width, height, GraphicsUnit.Pixel, imageAttributes);
510                                         graphics.Dispose();
511
512                                         list.Add(ReduceColorDepth(bitmap));
513                                 }
514
515                                 return index;
516                         }
517
518                         public void Clear()
519                         {
520                                 list.Clear();
521                         }
522
523                         public bool Contains(Image image)
524                         {
525                                 throw new NotSupportedException();
526                         }
527
528
529                         public IEnumerator GetEnumerator()
530                         {
531                                 Image[] images = new Image[list.Count];
532                                 int index;
533
534                                 for (index = 0; index < images.Length; index++)
535                                         images[index] = (Image)((Image)list[index]).Clone();
536
537                                 return images.GetEnumerator();
538                         }
539
540                         public int IndexOf(Image image)
541                         {
542                                 throw new NotSupportedException();
543                         }
544
545                         public void Remove(Image image)
546                         {
547                                 throw new NotSupportedException();
548                         }
549
550                         public void RemoveAt(int index)
551                         {
552                                 if (index < 0 || index >= list.Count)
553                                         throw new ArgumentOutOfRangeException("index");
554
555                                 list.RemoveAt(index);
556                         }
557                         #endregion // ImageCollection Public Instance Methods
558
559                         #region ImageCollection Interface Properties
560                         object IList.this[int index] {
561                                 get {
562                                         return this[index];
563                                 }
564
565                                 set {
566                                         if (!(value is Image))
567                                                 throw new ArgumentException("value");
568
569                                         this[index] = (Image)value;
570                                 }
571                         }
572
573                         bool IList.IsFixedSize {
574                                 get {
575                                         return false;
576                                 }
577                         }
578
579                         bool ICollection.IsSynchronized {
580                                 get {
581                                         return false;
582                                 }
583                         }
584
585                         object ICollection.SyncRoot {
586                                 get {
587                                         return this;
588                                 }
589                         }
590                         #endregion // ImageCollection Interface Properties
591
592                         #region ImageCollection Interface Methods
593                         int IList.Add(object value)
594                         {
595                                 int index;
596
597                                 if (!(value is Image))
598                                         throw new ArgumentException("value");
599
600                                 index = this.Count;
601                                 this.Add((Image)value);
602                                 return index;
603                         }
604
605                         bool IList.Contains(object value)
606                         {
607                                 return value is Image ? this.Contains((Image)value) : false;
608                         }
609
610                         int IList.IndexOf(object value)
611                         {
612                                 return value is Image ? this.IndexOf((Image)value) : -1;
613                         }
614
615                         void IList.Insert(int index, object value)
616                         {
617                                 throw new NotSupportedException();
618                         }
619
620                         void IList.Remove(object value)
621                         {
622                                 if (value is Image)
623                                         this.Remove((Image)value);
624                         }
625
626                         void ICollection.CopyTo(Array array, int index)
627                         {
628                                 int imageIndex;
629
630                                 for (imageIndex = 0; imageIndex < this.Count; imageIndex++)
631                                         array.SetValue(this[index], index++);
632                         }
633                         #endregion // ImageCollection Interface Methods
634                 }
635                 #endregion // Sub-classes
636
637                 #region Public Constructors
638                 public ImageList()
639                 {
640                         images = new ImageCollection(this);
641                 }
642
643                 public ImageList(System.ComponentModel.IContainer container) : this()
644                 {
645                         container.Add(this);
646                 }
647                 #endregion // Public Constructors
648
649                 private void OnRecreateHandle()
650                 {
651                         if (recreateHandle != null)
652                                 recreateHandle(this, EventArgs.Empty);
653                 }
654
655                 #region Public Instance Properties
656                 [DefaultValue(ColorDepth.Depth8Bit)]
657                 public ColorDepth ColorDepth {
658                         get {
659                                 return images.ColorDepth;
660                         }
661
662                         set {
663                                 images.ColorDepth = value;
664                         }
665                 }
666
667                 [Browsable(false)]
668                 [EditorBrowsable(EditorBrowsableState.Advanced)]
669                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
670                 public IntPtr Handle {
671                         get {
672                                 return images.Handle;
673                         }
674                 }
675
676                 [Browsable(false)]
677                 [EditorBrowsable(EditorBrowsableState.Advanced)]
678                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
679                 public bool HandleCreated {
680                         get {
681                                 return images.HandleCreated;
682                         }
683                 }
684
685                 [DefaultValue(null)]
686                 [MergableProperty(false)]
687                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
688                 public ImageCollection Images {
689                         get {
690                                 return this.images;
691                         }
692                 }
693
694                 [Localizable(true)]
695                 public Size ImageSize {
696                         get {
697                                 return images.ImageSize;
698                         }
699
700                         set {
701                                 images.ImageSize = value;
702                         }
703                 }
704
705                 [Browsable(false)]
706                 [DefaultValue(null)]
707                 [EditorBrowsable(EditorBrowsableState.Advanced)]
708                 public ImageListStreamer ImageStream {
709                         get {
710                                 return images.ImageStream;
711                         }
712
713                         set {
714                                 images.ImageStream = value;
715                         }
716                 }
717
718                 public Color TransparentColor {
719                         get {
720                                 return images.TransparentColor;
721                         }
722
723                         set {
724                                 images.TransparentColor = value;
725                         }
726                 }
727                 #endregion // Public Instance Properties
728
729                 #region Public Instance Methods
730                 public void Draw(Graphics g, Point pt, int index)
731                 {
732                         this.Draw(g, pt.X, pt.Y, index);
733                 }
734
735                 public void Draw(Graphics g, int x, int y, int index)
736                 {
737                         g.DrawImage(images.GetImage(index), x, y);
738                 }
739
740                 public void Draw(Graphics g, int x, int y, int width, int height, int index)
741                 {
742                         g.DrawImage(images.GetImage(index), x, y, width, height);
743                 }
744
745                 public override string ToString()
746                 {
747                         return base.ToString() + " Images.Count: " + images.Count.ToString() + ", ImageSize: " + images.ImageSize.ToString();
748                 }
749                 #endregion // Public Instance Methods
750
751                 #region Protected Instance Methods
752                 protected override void Dispose(bool disposing)
753                 {
754                         base.Dispose(disposing);
755                 }
756                 #endregion // Protected Instance Methods
757
758                 #region Events
759                 [Browsable(false)]
760                 [EditorBrowsable(EditorBrowsableState.Advanced)]
761                 public event EventHandler RecreateHandle {
762                         add {
763                                 recreateHandle += value;
764                         }
765
766                         remove {
767                                 recreateHandle -= value;
768                         }
769                 }
770                 #endregion // Events
771         }
772 }