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