- Same goes for setting the image size. Just resize them all
[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                                                         for (int i = 0; i < list.Count; i++) {
210                                                                 list [i] = ReduceColorDepth ((Bitmap) list [i]);
211                                                         }
212                                                         owner.OnRecreateHandle();
213                                                 }
214                                         }
215                                 }
216                         }
217
218                         // For use in ImageList
219                         internal IntPtr Handle {
220                                 get {
221                                         this.handleCreated = true;
222                                         return (IntPtr)(-1);
223                                 }
224                         }
225
226                         // For use in ImageList
227                         internal bool HandleCreated {
228                                 get {
229                                         return this.handleCreated;
230                                 }
231                         }
232
233                         // For use in ImageList
234                         internal Size ImageSize {
235                                 get {
236                                         return this.imageSize;
237                                 }
238
239                                 set {
240                                         if (value.Width < 1 || value.Width > 256 || value.Height < 1 || value.Height > 256)
241                                                 throw new ArgumentException("ImageSize.Width and Height must be between 1 and 256", "value");
242
243                                         if (this.imageSize != value) {
244                                                 this.imageSize = value;
245                                                 if (handleCreated) {
246                                                         for (int i = 0; i < list.Count; i++) {
247                                                                 list [i] = new Bitmap ((Image) list [i], imageSize);
248                                                         }
249                                                         owner.OnRecreateHandle();
250                                                 }
251                                         }
252                                 }
253                         }
254
255                         // For use in ImageList
256                         internal ImageListStreamer ImageStream {
257                                 get {
258                                         return list.Count == 0 ? null : new ImageListStreamer(this);
259                                 }
260
261                                 set {
262                                         int index;
263                                         Image[] streamImages;
264
265                                         if (value == null) {
266 #if NET_2_0
267                                                 this.handleCreated = false;
268                                                 list.Clear();
269 #endif
270                                         }
271                                         else if ((streamImages = value.Images) != null) {
272                                                 this.handleCreated = true;
273                                                 list.Clear();
274
275                                                 for (index = 0; index < streamImages.Length; index++)
276                                                         list.Add((Image)streamImages[index].Clone());
277
278                                                 this.imageSize = value.ImageSize;
279                                                 this.colorDepth = value.ColorDepth;
280 #if NET_2_0
281                                                 // Event is raised even when handle was not created yet.
282                                                 owner.OnRecreateHandle();
283 #endif
284                                         }
285                                 }
286                         }
287
288                         // For use in ImageList
289                         internal Color TransparentColor {
290                                 get {
291                                         return this.transparentColor;
292                                 }
293
294                                 set {
295                                         this.transparentColor = value;
296                                 }
297                         }
298                         #endregion // ImageCollection Internal Instance Properties
299
300                         #region ImageCollection Public Instance Properties
301                         [Browsable(false)]
302                         public int Count {
303                                 get {
304                                         return list.Count;
305                                 }
306                         }
307
308                         public bool Empty {
309                                 get {
310                                         return list.Count == 0;
311                                 }
312                         }
313
314                         public bool IsReadOnly {
315                                 get {
316                                         return false;
317                                 }
318                         }
319
320                         [Browsable(false)]
321                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
322                         public Image this[int index] {
323                                 get {
324                                         return (Image)GetImage(index).Clone();
325                                 }
326
327                                 set {
328                                         if (index < 0 || index >= list.Count)
329                                                 throw new ArgumentOutOfRangeException("index");
330
331                                         list[index] = CreateImage(value, this.transparentColor);
332                                 }
333                         }
334                         #endregion // ImageCollection Public Instance Properties
335
336                         #region ImageCollection Private Instance Methods
337                         private Image CreateImage(Image value, Color transparentColor)
338                         {
339                                 int width;
340                                 int height;
341                                 Bitmap bitmap;
342                                 Graphics graphics;
343                                 ImageAttributes imageAttributes;
344
345                                 if (value == null)
346                                         throw new ArgumentNullException("value");
347
348                                 if (!(value is Bitmap))
349                                         throw new ArgumentException("Image must be a Bitmap.");
350
351                                 if (transparentColor.A == 0)
352                                         imageAttributes = null;
353                                 else {
354                                         imageAttributes = new ImageAttributes();
355                                         imageAttributes.SetColorKey(transparentColor, transparentColor);
356                                 }
357
358                                 bitmap = new Bitmap(width = this.imageSize.Width, height = this.imageSize.Height, PixelFormat.Format32bppArgb);
359                                 graphics = Graphics.FromImage(bitmap);
360                                 graphics.DrawImage(value, new Rectangle(0, 0, width, height), 0, 0, value.Width, value.Height, GraphicsUnit.Pixel, imageAttributes);
361                                 graphics.Dispose();
362
363                                 return ReduceColorDepth(bitmap);
364                         }
365
366                         private unsafe Image ReduceColorDepth(Bitmap bitmap)
367                         {
368                                 byte* pixelPtr;
369                                 byte* lineEndPtr;
370                                 byte* linePtr;
371                                 int line;
372                                 int pixel;
373                                 int height;
374                                 int widthBytes;
375                                 int stride;
376                                 BitmapData bitmapData;
377                                 ArgbColor[] palette;
378
379                                 if (this.colorDepth < ColorDepth.Depth32Bit) {
380                                         bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
381                                         try {
382                                                 linePtr = (byte*)bitmapData.Scan0;
383                                                 height = bitmapData.Height;
384                                                 widthBytes = bitmapData.Width << 2;
385                                                 stride = bitmapData.Stride;
386
387                                                 if (this.colorDepth < ColorDepth.Depth16Bit) {
388                                                         palette = this.colorDepth < ColorDepth.Depth8Bit ? IndexedColorDepths.Palette4Bit : IndexedColorDepths.Palette8Bit;
389
390                                                         for (line = 0; line < height; line++) {
391                                                                 lineEndPtr = linePtr + widthBytes;
392                                                                 for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
393                                                                         *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : IndexedColorDepths.GetNearestColor(palette, pixel | AlphaMask);
394                                                                 linePtr += stride;
395                                                         }
396                                                 }
397                                                 else if (this.colorDepth < ColorDepth.Depth24Bit) {
398                                                         for (line = 0; line < height; line++) {
399                                                                 lineEndPtr = linePtr + widthBytes;
400                                                                 for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
401                                                                         *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : (pixel & 0x00F8F8F8) | AlphaMask;
402                                                                 linePtr += stride;
403                                                         }
404                                                 }
405                                                 else {
406                                                         for (line = 0; line < height; line++) {
407                                                                 lineEndPtr = linePtr + widthBytes;
408                                                                 for (pixelPtr = linePtr; pixelPtr < lineEndPtr; pixelPtr += 4)
409                                                                         *(int*)pixelPtr = ((pixel = *(int*)pixelPtr) & AlphaMask) == 0 ? 0x00000000 : pixel | AlphaMask;
410                                                                 linePtr += stride;
411                                                         }
412                                                 }
413                                         }
414                                         finally {
415                                                 bitmap.UnlockBits(bitmapData);
416                                         }
417                                 }
418
419                                 return bitmap;
420                         }
421                         #endregion // ImageCollection Private Instance Methods
422
423                         #region ImageCollection Internal Instance Methods
424                         // For use in ImageList
425                         internal Image GetImage(int index)
426                         {
427                                 if (index < 0 || index >= list.Count)
428                                         throw new ArgumentOutOfRangeException("index");
429
430                                 return (Image)list[index];
431                         }
432
433                         // For use in ImageListStreamer
434                         internal Image[] ToArray()
435                         {
436                                 Image[] images = new Image[list.Count];
437
438                                 list.CopyTo(images);
439                                 return images;
440                         }
441                         #endregion // ImageCollection Internal Instance Methods
442
443                         #region ImageCollection Public Instance Methods
444                         public void Add(Icon value)
445                         {
446                                 int width;
447                                 int height;
448                                 Bitmap bitmap;
449                                 Graphics graphics;
450
451                                 if (value == null)
452                                         throw new ArgumentNullException("value");
453
454                                 this.handleCreated = true;
455
456                                 bitmap = new Bitmap(width = this.imageSize.Width, height = this.imageSize.Height, PixelFormat.Format32bppArgb);
457                                 graphics = Graphics.FromImage(bitmap);
458                                 graphics.DrawIcon(value, new Rectangle(0, 0, width, height));
459                                 graphics.Dispose();
460
461                                 list.Add(ReduceColorDepth(bitmap));
462                         }
463
464                         public void Add(Image value)
465                         {
466                                 Add(value, this.transparentColor);
467                         }
468
469                         public int Add(Image value, Color transparentColor)
470                         {
471                                 this.handleCreated = true;
472                                 return list.Add(CreateImage(value, transparentColor));
473                         }
474
475                         public int AddStrip(Image value)
476                         {
477                                 int imageX;
478                                 int imageWidth;
479                                 int width;
480                                 int height;
481                                 int index;
482                                 Bitmap bitmap;
483                                 Graphics graphics;
484                                 Rectangle imageRect;
485                                 ImageAttributes imageAttributes;
486
487                                 if (value == null)
488                                         throw new ArgumentNullException("value");
489
490                                 if ((imageWidth = value.Width) == 0 || (imageWidth % (width = this.imageSize.Width)) != 0)
491                                         throw new ArgumentException("Width of image strip must be a positive multiple of ImageSize.Width.", "value");
492
493                                 if (value.Height != (height = this.imageSize.Height))
494                                         throw new ArgumentException("Height of image strip must be equal to ImageSize.Height.", "value");
495
496                                 if (!(value is Bitmap))
497                                         throw new ArgumentException("Image must be a Bitmap.");
498
499                                 this.handleCreated = true;
500
501                                 imageRect = new Rectangle(0, 0, width, height);
502                                 if (this.transparentColor.A == 0)
503                                         imageAttributes = null;
504                                 else {
505                                         imageAttributes = new ImageAttributes();
506                                         imageAttributes.SetColorKey(this.transparentColor, this.transparentColor);
507                                 }
508
509                                 index = list.Count;
510                                 for (imageX = 0; imageX < imageWidth; imageX += width) {
511                                         bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
512                                         graphics = Graphics.FromImage(bitmap);
513                                         graphics.DrawImage(value, imageRect, imageX, 0, width, height, GraphicsUnit.Pixel, imageAttributes);
514                                         graphics.Dispose();
515
516                                         list.Add(ReduceColorDepth(bitmap));
517                                 }
518
519                                 return index;
520                         }
521
522                         public void Clear()
523                         {
524                                 list.Clear();
525                         }
526
527                         public bool Contains(Image image)
528                         {
529                                 throw new NotSupportedException();
530                         }
531
532
533                         public IEnumerator GetEnumerator()
534                         {
535                                 Image[] images = new Image[list.Count];
536                                 int index;
537
538                                 for (index = 0; index < images.Length; index++)
539                                         images[index] = (Image)((Image)list[index]).Clone();
540
541                                 return images.GetEnumerator();
542                         }
543
544                         public int IndexOf(Image image)
545                         {
546                                 throw new NotSupportedException();
547                         }
548
549                         public void Remove(Image image)
550                         {
551                                 throw new NotSupportedException();
552                         }
553
554                         public void RemoveAt(int index)
555                         {
556                                 if (index < 0 || index >= list.Count)
557                                         throw new ArgumentOutOfRangeException("index");
558
559                                 list.RemoveAt(index);
560                         }
561                         #endregion // ImageCollection Public Instance Methods
562
563                         #region ImageCollection Interface Properties
564                         object IList.this[int index] {
565                                 get {
566                                         return this[index];
567                                 }
568
569                                 set {
570                                         if (!(value is Image))
571                                                 throw new ArgumentException("value");
572
573                                         this[index] = (Image)value;
574                                 }
575                         }
576
577                         bool IList.IsFixedSize {
578                                 get {
579                                         return false;
580                                 }
581                         }
582
583                         bool ICollection.IsSynchronized {
584                                 get {
585                                         return false;
586                                 }
587                         }
588
589                         object ICollection.SyncRoot {
590                                 get {
591                                         return this;
592                                 }
593                         }
594                         #endregion // ImageCollection Interface Properties
595
596                         #region ImageCollection Interface Methods
597                         int IList.Add(object value)
598                         {
599                                 int index;
600
601                                 if (!(value is Image))
602                                         throw new ArgumentException("value");
603
604                                 index = this.Count;
605                                 this.Add((Image)value);
606                                 return index;
607                         }
608
609                         bool IList.Contains(object value)
610                         {
611                                 return value is Image ? this.Contains((Image)value) : false;
612                         }
613
614                         int IList.IndexOf(object value)
615                         {
616                                 return value is Image ? this.IndexOf((Image)value) : -1;
617                         }
618
619                         void IList.Insert(int index, object value)
620                         {
621                                 throw new NotSupportedException();
622                         }
623
624                         void IList.Remove(object value)
625                         {
626                                 if (value is Image)
627                                         this.Remove((Image)value);
628                         }
629
630                         void ICollection.CopyTo(Array array, int index)
631                         {
632                                 int imageIndex;
633
634                                 for (imageIndex = 0; imageIndex < this.Count; imageIndex++)
635                                         array.SetValue(this[index], index++);
636                         }
637                         #endregion // ImageCollection Interface Methods
638                 }
639                 #endregion // Sub-classes
640
641                 #region Public Constructors
642                 public ImageList()
643                 {
644                         images = new ImageCollection(this);
645                 }
646
647                 public ImageList(System.ComponentModel.IContainer container) : this()
648                 {
649                         container.Add(this);
650                 }
651                 #endregion // Public Constructors
652
653                 private void OnRecreateHandle()
654                 {
655                         if (recreateHandle != null)
656                                 recreateHandle(this, EventArgs.Empty);
657                 }
658
659                 #region Public Instance Properties
660                 [DefaultValue(ColorDepth.Depth8Bit)]
661                 public ColorDepth ColorDepth {
662                         get {
663                                 return images.ColorDepth;
664                         }
665
666                         set {
667                                 images.ColorDepth = value;
668                         }
669                 }
670
671                 [Browsable(false)]
672                 [EditorBrowsable(EditorBrowsableState.Advanced)]
673                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
674                 public IntPtr Handle {
675                         get {
676                                 return images.Handle;
677                         }
678                 }
679
680                 [Browsable(false)]
681                 [EditorBrowsable(EditorBrowsableState.Advanced)]
682                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
683                 public bool HandleCreated {
684                         get {
685                                 return images.HandleCreated;
686                         }
687                 }
688
689                 [DefaultValue(null)]
690                 [MergableProperty(false)]
691                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
692                 public ImageCollection Images {
693                         get {
694                                 return this.images;
695                         }
696                 }
697
698                 [Localizable(true)]
699                 public Size ImageSize {
700                         get {
701                                 return images.ImageSize;
702                         }
703
704                         set {
705                                 images.ImageSize = value;
706                         }
707                 }
708
709                 [Browsable(false)]
710                 [DefaultValue(null)]
711                 [EditorBrowsable(EditorBrowsableState.Advanced)]
712                 public ImageListStreamer ImageStream {
713                         get {
714                                 return images.ImageStream;
715                         }
716
717                         set {
718                                 images.ImageStream = value;
719                         }
720                 }
721
722                 public Color TransparentColor {
723                         get {
724                                 return images.TransparentColor;
725                         }
726
727                         set {
728                                 images.TransparentColor = value;
729                         }
730                 }
731                 #endregion // Public Instance Properties
732
733                 #region Public Instance Methods
734                 public void Draw(Graphics g, Point pt, int index)
735                 {
736                         this.Draw(g, pt.X, pt.Y, index);
737                 }
738
739                 public void Draw(Graphics g, int x, int y, int index)
740                 {
741                         g.DrawImage(images.GetImage(index), x, y);
742                 }
743
744                 public void Draw(Graphics g, int x, int y, int width, int height, int index)
745                 {
746                         g.DrawImage(images.GetImage(index), x, y, width, height);
747                 }
748
749                 public override string ToString()
750                 {
751                         return base.ToString() + " Images.Count: " + images.Count.ToString() + ", ImageSize: " + images.ImageSize.ToString();
752                 }
753                 #endregion // Public Instance Methods
754
755                 #region Protected Instance Methods
756                 protected override void Dispose(bool disposing)
757                 {
758                         base.Dispose(disposing);
759                 }
760                 #endregion // Protected Instance Methods
761
762                 #region Events
763                 [Browsable(false)]
764                 [EditorBrowsable(EditorBrowsableState.Advanced)]
765                 public event EventHandler RecreateHandle {
766                         add {
767                                 recreateHandle += value;
768                         }
769
770                         remove {
771                                 recreateHandle -= value;
772                         }
773                 }
774                 #endregion // Events
775         }
776 }