**** Merged r40732-r40872 from MCS ****
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ImageList.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Peter Bartok    pbartok@novell.com
24 //
25
26
27 // COMPLETE
28
29 using System.Collections;
30 using System.ComponentModel;
31 using System.Drawing;
32 using System.Drawing.Imaging;
33
34 namespace System.Windows.Forms {
35         [DefaultProperty("Images")]
36         [Designer("System.Windows.Forms.Design.ImageListDesigner, " + Consts.AssemblySystem_Design)]
37         [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
38         [TypeConverter("System.Windows.Forms.ImageListConverter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
39         public sealed class ImageList : System.ComponentModel.Component {
40                 #region Local Variables
41                 private ColorDepth              color_depth;
42                 private ImageCollection         image_collection;
43                 private Size                    size;
44                 private Color                   transparency_color;
45                 private Delegate                handler;
46                 private ImageListStreamer       image_stream;
47                 #endregion      // Local Variables
48
49                 #region Sub-classes
50                 [Editor("System.Windows.Forms.Design.ImageCollectionEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
51                 public sealed class ImageCollection : IList, ICollection, IEnumerable {
52                         #region ImageCollection Local Variables
53                         private ImageList       owner;
54                         private ArrayList       list;
55                         #endregion      // ImageCollection Local Variables
56
57                         #region ImageCollection Private Constructors
58                         internal ImageCollection(ImageList owner) {
59                                 this.owner=owner;
60                                 this.list=new ArrayList();
61                         }
62                         #endregion      // ImageCollection Private Constructor
63
64                         #region ImageCollection Public Instance Properties
65                         [Browsable(false)]
66                         public int Count {
67                                 get {
68                                         return list.Count;
69                                 }
70                         }
71
72                         public bool Empty {
73                                 get {
74                                         return list.Count==0;
75                                 }
76                         }
77
78                         public bool IsReadOnly {
79                                 get {
80                                         return list.IsReadOnly;
81                                 }
82                         }
83
84                         [Browsable(false)]
85                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
86                         public Image this[int index] {
87                                 get {
88                                         if (index<0 || index>=list.Count) {
89                                                 throw new ArgumentOutOfRangeException("index", index, "ImageCollection does not have that many images");
90                                         }
91                                         return (Image)list[index];
92                                 }
93
94                                 set {
95                                         if (index<0 || index>=list.Count) {
96                                                 throw new ArgumentOutOfRangeException("index", index, "ImageCollection does not have that many images");
97                                         }
98
99                                         if (value==null) {
100                                                 throw new ArgumentOutOfRangeException("value", value, "Image cannot be null");
101                                         }
102
103                                         list[index]=value;
104                                         // What happens if the bitmap had a previous 'MakeTransparent' done to it?
105                                         ((Bitmap)list[index]).MakeTransparent(owner.transparency_color);
106                                 }
107                         }
108                         #endregion      // ImageCollection Public Instance Properties
109
110                         #region ImageCollection Private Instance Methods
111                         private int AddInternal(Image image) {
112                                 int             width;
113                                 int             height;
114                                 PixelFormat     format;
115
116                                 width=owner.ImageSize.Width;
117                                 height=owner.ImageSize.Height;
118                                 switch(owner.color_depth) {
119                                         case ColorDepth.Depth4Bit:      format=PixelFormat.Format4bppIndexed; break;
120                                         case ColorDepth.Depth8Bit:      format=PixelFormat.Format8bppIndexed; break;
121                                         case ColorDepth.Depth16Bit:     format=PixelFormat.Format16bppRgb555; break;
122                                         case ColorDepth.Depth24Bit:     format=PixelFormat.Format24bppRgb; break;
123                                         case ColorDepth.Depth32Bit:     format=PixelFormat.Format32bppArgb; break;
124                                         default:                        format=PixelFormat.Format32bppArgb; break;
125                                 }
126
127                                 // Check if we can add straight or if we have to resize
128                                 if (image.Width!=width || image.Height!=height || image.PixelFormat!=format) {
129                                         Graphics        g;
130                                         Bitmap          reformatted_image;
131
132                                         reformatted_image = new Bitmap(width, height, format);
133                                         g=Graphics.FromImage(reformatted_image);
134
135                                         g.DrawImage(image, new Rectangle(0, 0, width, height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
136                                         g.Dispose();
137
138                                         return list.Add(reformatted_image);
139                                 } else {
140                                         return list.Add(image);
141                                 }
142                         }
143
144                         internal void Dispose() {
145 #if dontwantthis
146                                 if (list!=null) {
147                                         for (int i=0; i<list.Count; i++) {
148                                                 ((Image)list[i]).Dispose();
149                                         }
150                                 }
151 #endif
152                         }
153                         #endregion      // ImageCollection Private Instance Methods
154
155                         #region ImageCollection Public Instance Methods
156                         public int Add(Image value, Color transparentColor) {
157                                 if (value==null) {
158                                         throw new ArgumentNullException("value", "Cannot add null image");
159                                 }
160
161                                 ((Bitmap)value).MakeTransparent(owner.transparency_color);
162                                 return AddInternal(value);
163                                 
164                         }
165
166                         public void Add(Icon value) {
167                                 Image image;
168
169                                 image = value.ToBitmap();
170
171                                 if (value==null || image==null) {
172                                         throw new ArgumentNullException("value", "Cannot add null icon");
173                                 }
174
175                                 ((Bitmap)image).MakeTransparent(owner.transparency_color);
176                                 AddInternal(image);
177                         }
178
179                         public void Add(Image value) {
180                                 if (value==null) {
181                                         throw new ArgumentNullException("value", "Cannot add null image");
182                                 }
183                                 ((Bitmap)value).MakeTransparent(owner.transparency_color);
184                                 AddInternal(value);
185                         }
186
187                         public int AddStrip(Image value) {
188                                 int             image_count;
189                                 int             width;
190                                 int             height;
191                                 Bitmap          image;
192                                 Graphics        g;
193
194                                 if (value==null) {
195                                         throw new ArgumentNullException("value", "Cannot add null images");
196                                 }
197
198                                 if ((value.Width % owner.ImageSize.Width) != 0) {
199                                         throw new ArgumentException("Strip is not a multiple of the ImageList with", "value");
200                                 }
201
202                                 // MSDN: The number of images is inferred from the width. A strip is multiple images side-by-side
203                                 width=owner.ImageSize.Width;
204                                 height=owner.ImageSize.Height;
205                                 image_count=value.Width/width;
206                                 for (int i=0; i<image_count; i++) {
207                                         image = new Bitmap(value, width, height);
208                                         g = Graphics.FromImage(image);
209
210                                         g.DrawImage(value, new Rectangle(0, 0, width, height), i*width, 0, width, height, GraphicsUnit.Pixel);
211                                         AddInternal(image);
212
213                                         g.Dispose();
214                                         image.Dispose();
215                                 }
216
217                                 // FIXME - is this right? MSDN says to return the index, but we might have multiple...
218                                 return image_count;
219                         }
220
221                         public void Clear() {
222                                 list.Clear();
223                         }
224
225                         public bool Contains(Image image) {
226                                 return list.Contains(image);
227                         }
228
229                         public IEnumerator GetEnumerator() {
230                                 return list.GetEnumerator();
231                         }
232
233                         public int IndexOf(Image image) {
234                                 return list.IndexOf(image);
235                         }
236
237                         public void Remove(Image image) {
238                                 list.Remove(image);
239                         }
240
241                         public void RemoveAt(int index) {
242                                 if (index<0 || index>=list.Count) {
243                                         throw new ArgumentOutOfRangeException("index", index, "ImageCollection does not have that many images");
244                                 }
245
246                                 list.RemoveAt(index);
247                         }
248                         #endregion      // ImageCollection Public Instance Methods
249
250                         #region ImageCollection Interface Properties
251                         object IList.this[int index] {
252                                 get {
253                                         if (index<0 || index>=list.Count) {
254                                                 throw new ArgumentOutOfRangeException("index", index, "ImageCollection does not have that many images");
255                                         }
256                                         return this[index];
257                                 }
258
259                                 set {
260                                         if (!(value is Bitmap)) {
261                                                 throw new ArgumentException("Object of type Image required", "value");
262                                         }
263
264                                         this[index]=(Image)value;
265                                 }
266                         }
267
268                         bool IList.IsFixedSize {
269                                 get {
270                                         return false;
271                                 }
272                         }
273
274                         bool IList.IsReadOnly {
275                                 get {
276                                         return list.IsReadOnly;
277                                 }
278                         }
279
280                         bool ICollection.IsSynchronized {
281                                 get {
282                                         return list.IsSynchronized;
283                                 }
284                         }
285
286                         object ICollection.SyncRoot {
287                                 get {
288                                         return list.SyncRoot;
289                                 }
290                         }
291                         #endregion      // ImageCollection Interface Properties
292
293                         #region ImageCollection Interface Methods
294                         int IList.Add(object value) {
295                                 if (value == null) {
296                                         throw new ArgumentNullException("value", "Cannot add null images");
297                                 }
298
299                                 if (!(value is Bitmap)) {
300                                         throw new ArgumentException("Object of type Image required", "value");
301                                 }
302
303                                 return list.Add(value);
304                         }
305
306                         bool IList.Contains(object value) {
307                                 if (!(value is Bitmap)) {
308                                         throw new ArgumentException("Object of type Image required", "value");
309                                 }
310
311                                 return this.Contains((Image) value);
312                         }
313
314                         int IList.IndexOf(object value) {
315                                 if (!(value is Bitmap)) {
316                                         throw new ArgumentException("Object of type Image required", "value");
317                                 }
318
319                                 return this.IndexOf((Image) value);
320                         }
321
322                         void IList.Insert(int index, object value) {
323                                 if (!(value is Bitmap)) {
324                                         throw new ArgumentException("Object of type Image required", "value");
325                                 }
326                                 list.Insert(index, value);
327                         }
328
329                         void IList.Remove(object value) {
330                                 if (!(value is Bitmap)) {
331                                         throw new ArgumentException("Object of type Image required", "value");
332                                 }
333                                 list.Remove(value);
334                         }
335
336                         void ICollection.CopyTo(Array array, int index) {
337                                 if (list.Count>0) {
338                                         list.CopyTo(array, index);
339                                 }
340                         }
341                         #endregion      // ImageCollection Interface Methods
342                 }
343                 #endregion      // Sub-classes
344
345                 #region Public Constructors
346                 public ImageList() {
347                         color_depth = ColorDepth.Depth8Bit;
348                         transparency_color = Color.Transparent;
349                         size = new Size(16, 16);
350                         image_collection = new ImageCollection(this);
351                 }
352
353                 public ImageList(System.ComponentModel.IContainer container) : this ()
354                 {
355                         color_depth = ColorDepth.Depth8Bit;
356                         transparency_color = Color.Transparent;
357                         size = new Size(16, 16);
358                         container.Add (this);
359                 }
360                 #endregion      // Public Constructors
361
362                 #region Public Instance Properties
363                 [DefaultValue(ColorDepth.Depth8Bit)]
364                 public ColorDepth ColorDepth {
365                         get {
366                                 return this.color_depth;
367                         }
368
369                         set {
370                                 this.color_depth=value;
371                         }
372                 }
373
374                 [MonoTODO("Determine if we support HBITMAP handles, this would involve XplatUI")]
375                 [Browsable(false)]
376                 [EditorBrowsable(EditorBrowsableState.Advanced)]
377                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
378                 public IntPtr Handle {
379                         get {
380                                 if (RecreateHandle!=null) RecreateHandle(this, EventArgs.Empty);
381                                 return IntPtr.Zero;
382                         }
383                 }
384
385                 [MonoTODO("Determine if we support HBITMAP handles, this would involve XplatUI")]
386                 [Browsable(false)]
387                 [EditorBrowsable(EditorBrowsableState.Advanced)]
388                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
389                 public bool HandleCreated {
390                         get {
391                                 return false;
392                         }
393                 }
394
395                 [DefaultValue(null)]
396                 [MergableProperty(false)]
397                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
398                 public ImageCollection Images {
399                         get {
400                                 return this.image_collection;
401                         }
402                 }
403
404                 [Localizable(true)]
405                 public Size ImageSize {
406                         get {
407                                 return this.size;
408                         }
409
410                         set {
411                                 if (value.Width<1 || value.Width>256 || value.Height<1 || value.Height>256) {
412                                         throw new ArgumentException("ImageSize width and height must be between 1 and 255", "value");
413                                 }
414                                 this.size=value;
415                         }
416                 }
417
418                 [Browsable(false)]
419                 [DefaultValue(null)]
420                 [EditorBrowsable(EditorBrowsableState.Advanced)]
421                 public ImageListStreamer ImageStream {
422                         get {
423                                 return image_stream;
424                         }
425
426                         set {
427                                 image_stream = value;
428
429                                 size = image_stream.ImageSize;
430                                 color_depth = image_stream.ImageColorDepth;
431                                 transparency_color = image_stream.BackColor;
432
433                                 image_collection.Clear ();
434
435                                 foreach (Image image in image_stream.Images)
436                                         image_collection.Add (image);
437                         }
438                 }
439
440                 public Color TransparentColor {
441                         get {
442                                 return this.transparency_color;
443                         }
444
445                         set {
446                                 this.transparency_color=value;
447                         }
448                 }
449                 #endregion      // Public Instance Properties
450
451                 #region Public Instance Methods
452                 public void Draw(Graphics g, Point pt, int index) {
453                         this.Draw(g, pt.X, pt.Y, index);
454                 }
455
456                 public void Draw(Graphics g, int x, int y, int index) {
457                         this.Draw(g, x, y, this.size.Width, this.size.Height, index);
458                 }
459
460                 public void Draw(Graphics g, int x, int y, int width, int height, int index) {
461                         Image   i;
462
463                         if ((index < 0) || (index >= this.Images.Count)) {
464                                 throw new ArgumentOutOfRangeException("index", index, "ImageList does not contain that many images");
465                         }
466                         i = this.Images[index];
467                         g.DrawImage(i, x, y, width, height);
468                 }
469
470                 public override string ToString() {\r
471                         return "ImageList Size "+this.size.Width.ToString()+"x"+this.size.Height.ToString()+", Depth "+this.color_depth.ToString()+", Transparency color "+this.transparency_color.ToString();\r
472                 }
473                 #endregion      // Public Instance Methods
474
475                 #region Protected Instance Methods
476                 protected override void Dispose(bool disposing) {\r
477                         if (image_collection!=null) {\r
478                                 image_collection.Dispose();\r
479                         }\r
480                 }\r
481
482                 #endregion      // Protected Instance Methods
483
484                 #region Events
485                 [Browsable(false)]
486                 [EditorBrowsable(EditorBrowsableState.Advanced)]
487                 public event EventHandler RecreateHandle;
488                 #endregion      // Events
489         }
490 }