2007-08-28 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / PictureBox.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 //      Jackson Harper (jackson@ximian.com)
24 //
25
26 // COMPLETE
27
28 using System;
29 using System.ComponentModel;
30 using System.ComponentModel.Design;
31 using System.Drawing;
32 using System.Drawing.Imaging;
33 using System.Runtime.InteropServices;
34 using System.IO;
35 using System.Net;
36
37 namespace System.Windows.Forms {
38         [DefaultProperty("Image")]
39         [Designer("System.Windows.Forms.Design.PictureBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
40 #if NET_2_0
41         [Docking (DockingBehavior.Ask)]
42         [ClassInterface (ClassInterfaceType.AutoDispatch)]
43         [ComVisible (true)]
44         [DefaultBindingProperty ("Image")]
45 #endif
46         public class PictureBox : Control 
47 #if NET_2_0
48                                         , ISupportInitialize
49 #endif
50         {
51                 #region Fields
52                 private Image   image;
53                 private PictureBoxSizeMode size_mode;
54 #if NET_2_0
55                 private Image   error_image;
56                 private string  image_location;
57                 private Image   initial_image;
58                 private bool    wait_on_load;
59                 private WebClient image_download;
60 #endif
61                 private int     no_update;
62                 #endregion      // Fields
63
64                 private EventHandler frame_handler;
65
66                 #region Public Constructor
67                 public PictureBox ()
68                 {
69                         //recalc = true;
70 #if NET_2_0
71                         SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
72 #else
73                         SetStyle (ControlStyles.DoubleBuffer, true);
74 #endif
75                         SetStyle (ControlStyles.Opaque, false);
76                         SetStyle (ControlStyles.Selectable, false);
77                         SetStyle (ControlStyles.SupportsTransparentBackColor, true);
78                         HandleCreated += new EventHandler(PictureBox_HandleCreated);
79 #if NET_2_0
80                         initial_image = ResourceImageLoader.Get ("image-x-generic.png");
81                         error_image = ResourceImageLoader.Get ("image-missing.png");
82 #endif
83                 }
84                 #endregion      // Public Constructor
85
86                 #region Public Properties
87                 [DefaultValue(PictureBoxSizeMode.Normal)]
88                 [Localizable(true)]
89                 [RefreshProperties(RefreshProperties.Repaint)]
90                 public PictureBoxSizeMode SizeMode {
91                         get { return size_mode; }
92                         set {
93                                 if (size_mode == value)
94                                         return;
95                                 size_mode = value;
96                                 
97 #if NET_2_0
98                                 if (size_mode == PictureBoxSizeMode.AutoSize) {
99                                         AutoSize = true;
100                                         SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
101                                 } else {
102                                         AutoSize = false;
103                                         SetAutoSizeMode (AutoSizeMode.GrowOnly);
104                                 }
105 #endif
106                                 UpdateSize ();
107                                 if (no_update == 0) {
108                                         Invalidate ();
109                                 }
110
111                                 OnSizeModeChanged (EventArgs.Empty);
112                         }
113                 }
114
115 #if NET_2_0
116                 [Bindable (true)]
117 #else
118                 [DefaultValue(null)]
119 #endif
120                 [Localizable(true)]
121                 public Image Image {
122                         get { return image; }
123                         set {
124                                 StopAnimation ();
125
126                                 image = value;
127
128                                 if (IsHandleCreated) {
129                                         UpdateSize ();
130                                         if (image != null && ImageAnimator.CanAnimate (image)) {
131                                                 frame_handler = new EventHandler (OnAnimateImage);
132                                                 ImageAnimator.Animate (image, frame_handler);
133                                         }
134                                         if (no_update == 0) {
135                                                 Invalidate ();
136                                         }
137                                 }
138                         }
139                 }
140
141                 [DefaultValue(BorderStyle.None)]
142                 [DispId(-504)]
143                 public BorderStyle BorderStyle {
144                         get { return InternalBorderStyle; }
145                         set { InternalBorderStyle = value; }
146                 }
147
148                 [Browsable(false)]
149                 [EditorBrowsable(EditorBrowsableState.Never)]
150                 public new bool CausesValidation {
151                         get { return base.CausesValidation; }
152                         set { base.CausesValidation = value; }
153                 }
154
155 #if NET_2_0
156                 [Localizable (true)]
157                 [RefreshProperties (RefreshProperties.All)]
158                 public Image ErrorImage {
159                         get { return error_image; }
160                         set { error_image = value; }
161                 }
162                 
163                 [RefreshProperties (RefreshProperties.All)]
164                 [Localizable(true)]
165                 public Image InitialImage {
166                         get { return initial_image; }
167                         set { initial_image = value; }
168                 }
169                 
170                 [Localizable (true)]
171                 [DefaultValue (null)]
172                 [RefreshProperties (RefreshProperties.All)]
173                 public string ImageLocation {
174                         get { return image_location; }
175                         set { image_location = value; }
176                 }
177                 
178                 [Localizable (true)]
179                 [DefaultValue (false)]
180                 public bool WaitOnLoad {
181                         get { return wait_on_load; }
182                         set { wait_on_load = value; }
183                 }
184 #endif
185
186                 [Browsable(false)]
187                 [EditorBrowsable(EditorBrowsableState.Never)]
188                 public new ImeMode ImeMode {
189                         get { return base.ImeMode; }
190                         set { base.ImeMode = value; }
191                 }
192
193                 [Browsable(false)]
194                 [EditorBrowsable(EditorBrowsableState.Never)]
195                 public override RightToLeft RightToLeft {
196                         get { return base.RightToLeft; }
197                         set { base.RightToLeft = value; }
198                 }
199
200                 [Browsable(false)]
201                 [EditorBrowsable(EditorBrowsableState.Never)]
202                 public new int TabIndex {
203                         get { return base.TabIndex; }
204                         set { base.TabIndex = value; }
205                 }
206
207                 [Browsable(false)]
208                 [EditorBrowsable(EditorBrowsableState.Never)]
209                 public new bool TabStop {
210                         get { return base.TabStop; }
211                         set { base.TabStop = value; }
212                 }
213
214                 [Bindable(false)]
215                 [Browsable(false)]
216                 [EditorBrowsable(EditorBrowsableState.Never)]
217                 public override string Text {
218                         get { return base.Text; }
219                         set { base.Text = value; }
220                 }
221
222                 protected override CreateParams CreateParams {
223                         get {
224                                 return base.CreateParams;
225                         }
226                 }
227
228                 protected override ImeMode DefaultImeMode {
229                         get { return base.DefaultImeMode; }
230                 }
231
232                 [Browsable(false)]
233                 [EditorBrowsable(EditorBrowsableState.Never)]
234                 public override Font Font {
235                         get { return base.Font; }
236                         set { base.Font = value; }
237                 }
238
239                 [Browsable(false)]
240                 [EditorBrowsable(EditorBrowsableState.Never)]
241                 public override Color ForeColor {
242                         get { return base.ForeColor; }
243                         set { base.ForeColor = value; }
244                 }
245
246                 [Browsable(false)]
247                 [EditorBrowsable(EditorBrowsableState.Never)]
248                 public override bool AllowDrop {
249                         get { return base.AllowDrop; }
250                         set { base.AllowDrop = value; }
251                 }
252                 #endregion      // Public Properties
253
254                 #region Protected Instance Methods
255                 protected override Size DefaultSize {
256                         get { return ThemeEngine.Current.PictureBoxDefaultSize; }
257                 }
258
259                 protected override void Dispose (bool disposing)
260                 {
261                         if (image != null) {
262                                 StopAnimation ();
263                                 image = null;
264                         }
265 #if NET_2_0
266                         initial_image = null;
267 #endif
268
269                         base.Dispose (disposing);
270                 }
271
272                 protected override void OnPaint (PaintEventArgs pe)
273                 {
274                         ThemeEngine.Current.DrawPictureBox (pe.Graphics, pe.ClipRectangle, this);
275                         base.OnPaint (pe);
276                 }
277
278                 protected override void OnVisibleChanged (EventArgs e)
279                 {
280                         base.OnVisibleChanged (e);
281                 }
282
283                 protected virtual void OnSizeModeChanged (EventArgs e)
284                 {
285                         EventHandler eh = (EventHandler)(Events [SizeModeChangedEvent]);
286                         if (eh != null)
287                                 eh (this, e);
288                 }
289
290                 protected override void OnEnabledChanged (EventArgs e)
291                 {
292                         base.OnEnabledChanged (e);
293                 }
294
295 #if NET_2_0
296                 [EditorBrowsable (EditorBrowsableState.Advanced)]
297                 protected override void OnHandleCreated (EventArgs e)
298                 {
299                         base.OnHandleCreated (e);
300                 }
301
302                 [EditorBrowsable (EditorBrowsableState.Advanced)]
303                 protected override void OnHandleDestroyed (EventArgs e)
304                 {
305                         base.OnHandleDestroyed (e);
306                 }
307                 
308                 protected virtual void OnLoadCompleted (AsyncCompletedEventArgs e)
309                 {
310                         AsyncCompletedEventHandler eh = (AsyncCompletedEventHandler)(Events[LoadCompletedEvent]);
311                         if (eh != null)
312                                 eh (this, e);
313                 }
314                 
315                 protected virtual void OnLoadProgressChanged (ProgressChangedEventArgs e)
316                 {
317                         ProgressChangedEventHandler eh = (ProgressChangedEventHandler)(Events[LoadProgressChangedEvent]);
318                         if (eh != null)
319                                 eh (this, e);
320                 }
321 #endif
322
323                 protected override void OnParentChanged (EventArgs e)
324                 {
325                         base.OnParentChanged (e);
326                 }
327
328                 protected override void OnResize (EventArgs e)
329                 {
330                         base.OnResize (e);
331
332                         if (size_mode == PictureBoxSizeMode.CenterImage || size_mode == PictureBoxSizeMode.StretchImage)
333                                 Refresh ();
334 #if NET_2_0
335                         if (size_mode == PictureBoxSizeMode.Zoom)
336                                 Refresh ();
337 #endif
338                 }
339
340 #if NET_2_0
341                 internal override Size GetPreferredSizeCore (Size proposedSize)
342                 {
343                         if (image == null)
344                                 return base.GetPreferredSizeCore (proposedSize);
345                         else
346                                 return image.Size;
347                 }
348 #else
349                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
350                 {
351                         if (size_mode == PictureBoxSizeMode.AutoSize && image != null) {
352                                 width = image.Width;
353                                 height = image.Height;
354                         }
355                         base.SetBoundsCore (x, y, width, height, specified);
356                 }
357 #endif
358                 #endregion      // Protected Instance Methods
359
360 #if NET_2_0
361                 #region ISupportInitialize Interface
362                 void System.ComponentModel.ISupportInitialize.BeginInit() {
363                         no_update++;
364                 }
365
366                 void System.ComponentModel.ISupportInitialize.EndInit() {
367                         if (no_update > 0) {
368                                 no_update--;
369                         }
370                         if (no_update == 0) {
371                                 Invalidate ();
372                         }
373                 }
374                 #endregion      // ISupportInitialize Interface
375 #endif
376
377                 #region Private Properties
378 #if NET_2_0
379                 private WebClient ImageDownload {
380                         get { 
381                                 if (image_download == null)
382                                         image_download = new WebClient ();
383                                         
384                                 return image_download;
385                         }
386                 }
387 #endif
388                 #endregion
389                 
390                 #region Private Methods
391                 private void StopAnimation ()
392                 {
393                         if (frame_handler == null)
394                                 return;
395                         ImageAnimator.StopAnimate (image, frame_handler);
396                         frame_handler = null;
397                 }
398
399                 private void UpdateSize ()
400                 {
401                         if (image == null)
402                                 return;
403 #if NET_2_0
404                         if (Parent != null)
405                                 Parent.PerformLayout (this, "AutoSize");
406 #else
407                         if (size_mode == PictureBoxSizeMode.AutoSize)
408                                 ClientSize = image.Size; 
409 #endif
410                 }
411
412                 private void OnAnimateImage (object sender, EventArgs e)
413                 {
414                         // This is called from a worker thread,BeginInvoke is used
415                         // so the control is updated from the correct thread
416                         
417                         // Check if we have a handle again, since it may have gotten
418                         // destroyed since the last time we checked.
419                         if (!IsHandleCreated)
420                                 return;
421                         
422                         BeginInvoke (new EventHandler (UpdateAnimatedImage), new object [] { this, e });
423                 }
424
425                 private void UpdateAnimatedImage (object sender, EventArgs e)
426                 {
427                         // Check if we have a handle again, since it may have gotten
428                         // destroyed since the last time we checked.
429                         if (!IsHandleCreated)
430                                 return;
431                                 
432                         ImageAnimator.UpdateFrames (image);
433                         Refresh ();
434                 }
435
436                 private void PictureBox_HandleCreated(object sender, EventArgs e) {
437                         UpdateSize ();
438                         if (image != null && ImageAnimator.CanAnimate (image)) {
439                                 frame_handler = new EventHandler (OnAnimateImage);
440                                 ImageAnimator.Animate (image, frame_handler);
441                         }
442                         if (no_update == 0) {
443                                 Invalidate ();
444                         }
445                 }
446                 
447 #if NET_2_0
448                 void ImageDownload_DownloadDataCompleted (object sender, DownloadDataCompletedEventArgs e)
449                 {
450                         if (e.Error != null && !e.Cancelled)
451                                 Image = error_image;
452                         else if (e.Error == null && !e.Cancelled)
453                                 using (MemoryStream ms = new MemoryStream (e.Result))
454                                         Image = Image.FromStream (ms);
455                                         
456                         ImageDownload.DownloadProgressChanged -= new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
457                         ImageDownload.DownloadDataCompleted -= new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
458                         image_download = null;
459                         
460                         OnLoadCompleted (e);
461                 }
462
463                 private void ImageDownload_DownloadProgressChanged (object sender, DownloadProgressChangedEventArgs e)
464                 {
465                         OnLoadProgressChanged (new ProgressChangedEventArgs (e.ProgressPercentage, e.UserState));
466                 }
467 #endif
468                 #endregion      // Private Methods
469
470                 #region Public Instance Methods
471 #if NET_2_0
472                 public void CancelAsync ()
473                 {
474                         if (image_download != null)
475                                 image_download.CancelAsync ();
476                 }
477                 
478                 public void Load ()
479                 {
480                         Load (image_location);
481                 }
482                 
483                 public void Load (string url)
484                 {
485                         if (string.IsNullOrEmpty (url))
486                                 throw new InvalidOperationException ("ImageLocation not specified.");
487                         
488                         image_location = url;
489                         
490                         if (url.Contains ("://"))
491                                 using (Stream s = ImageDownload.OpenRead (url))
492                                         Image = Image.FromStream (s);
493                         else
494                                 Image = Image.FromFile (url);
495                 }
496                 
497                 public void LoadAsync ()
498                 {
499                         LoadAsync (image_location);
500                 }
501                 
502                 public void LoadAsync (string url)
503                 {
504                         // If WaitOnLoad is true, do not do async
505                         if (wait_on_load) {
506                                 Load (url);
507                                 return;
508                         }
509                         image_location = url;
510                         Image = InitialImage;
511                         
512                         if (ImageDownload.IsBusy)
513                                 ImageDownload.CancelAsync ();
514
515                         ImageDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
516                         ImageDownload.DownloadDataCompleted += new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
517                         ImageDownload.DownloadDataAsync (new Uri (url));
518                 }
519 #endif
520                 public override string ToString() {
521                         return String.Format("{0}, SizeMode: {1}", base.ToString (), SizeMode);
522                 }
523                 #endregion
524
525                 #region Events
526                 [Browsable(false)]
527                 [EditorBrowsable(EditorBrowsableState.Never)]
528                 public new event EventHandler CausesValidationChanged {
529                         add { base.CausesValidationChanged += value; }
530                         remove { base.CausesValidationChanged -= value; }
531                 }
532
533                 [Browsable(false)]
534                 [EditorBrowsable(EditorBrowsableState.Never)]
535                 public new event EventHandler Enter {
536                         add { base.Enter += value; }
537                         remove { base.Enter -= value; }
538                 }
539
540                 [Browsable(false)]
541                 [EditorBrowsable(EditorBrowsableState.Never)]
542                 public new event EventHandler FontChanged {
543                         add { base.FontChanged += value; }
544                         remove { base.FontChanged -= value; }
545                 }
546
547                 [Browsable(false)]
548                 [EditorBrowsable(EditorBrowsableState.Never)]
549                 public new event EventHandler ForeColorChanged {
550                         add { base.ForeColorChanged += value; }
551                         remove { base.ForeColorChanged -= value; }
552                 }
553
554                 [Browsable(false)]
555                 [EditorBrowsable(EditorBrowsableState.Never)]
556                 public new event EventHandler ImeModeChanged {
557                         add { base.ImeModeChanged += value; }
558                         remove { base.ImeModeChanged -= value; }
559                 }
560
561                 [Browsable(false)]
562                 [EditorBrowsable(EditorBrowsableState.Never)]
563                 public new event KeyEventHandler KeyDown {
564                         add { base.KeyDown += value; }
565                         remove { base.KeyDown -= value; }
566                 }
567
568                 [Browsable(false)]
569                 [EditorBrowsable(EditorBrowsableState.Never)]
570                 public new event KeyPressEventHandler KeyPress {
571                         add { base.KeyPress += value; }
572                         remove { base.KeyPress -= value; }
573                 }
574
575                 [Browsable(false)]
576                 [EditorBrowsable(EditorBrowsableState.Never)]
577                 public new event KeyEventHandler KeyUp {
578                         add { base.KeyUp += value; }
579                         remove { base.KeyUp -= value; }
580                 }
581
582                 [Browsable(false)]
583                 [EditorBrowsable(EditorBrowsableState.Never)]
584                 public new event EventHandler Leave {
585                         add { base.Leave += value; }
586                         remove { base.Leave -= value; }
587                 }
588
589 #if NET_2_0
590                 static object LoadCompletedEvent = new object ();
591                 static object LoadProgressChangedEvent = new object ();
592
593                 public event AsyncCompletedEventHandler LoadCompleted {
594                         add { Events.AddHandler (LoadCompletedEvent, value); }
595                         remove { Events.RemoveHandler (LoadCompletedEvent, value); }
596                 }
597
598                 public event ProgressChangedEventHandler LoadProgressChanged {
599                         add { Events.AddHandler (LoadProgressChangedEvent, value); }
600                         remove { Events.RemoveHandler (LoadProgressChangedEvent, value); }
601                 }
602 #endif
603
604                 [Browsable(false)]
605                 [EditorBrowsable(EditorBrowsableState.Never)]
606                 public new event EventHandler RightToLeftChanged {
607                         add { base.RightToLeftChanged += value; }
608                         remove { base.RightToLeftChanged -= value; }
609                 }
610
611                 [Browsable(false)]
612                 [EditorBrowsable(EditorBrowsableState.Never)]
613                 public new event EventHandler TabIndexChanged {
614                         add { base.TabIndexChanged += value; }
615                         remove { base.TabIndexChanged -= value; }
616                 }
617
618                 [Browsable(false)]
619                 [EditorBrowsable(EditorBrowsableState.Never)]
620                 public new event EventHandler TabStopChanged {
621                         add { base.TabStopChanged += value; }
622                         remove { base.TabStopChanged -= value; }
623                 }
624
625                 [Browsable(false)]
626                 [EditorBrowsable(EditorBrowsableState.Never)]
627                 public new event EventHandler TextChanged {
628                         add { base.TextChanged += value; }
629                         remove { base.TextChanged -= value; }
630                 }
631
632                 static object SizeModeChangedEvent = new object ();
633                 public event EventHandler SizeModeChanged {
634                         add { Events.AddHandler (SizeModeChangedEvent, value); }
635                         remove { Events.RemoveHandler (SizeModeChangedEvent, value); }
636                 }
637
638                 #endregion      // Events
639         }
640 }
641