svn path=/trunk/mcs/; revision=104772
[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 {
176                                 image_location = value;
177                                 Load (value);
178                         }
179                 }
180                 
181                 [Localizable (true)]
182                 [DefaultValue (false)]
183                 public bool WaitOnLoad {
184                         get { return wait_on_load; }
185                         set { wait_on_load = value; }
186                 }
187 #endif
188
189                 [Browsable(false)]
190                 [EditorBrowsable(EditorBrowsableState.Never)]
191                 public new ImeMode ImeMode {
192                         get { return base.ImeMode; }
193                         set { base.ImeMode = value; }
194                 }
195
196                 [Browsable(false)]
197                 [EditorBrowsable(EditorBrowsableState.Never)]
198                 public override RightToLeft RightToLeft {
199                         get { return base.RightToLeft; }
200                         set { base.RightToLeft = value; }
201                 }
202
203                 [Browsable(false)]
204                 [EditorBrowsable(EditorBrowsableState.Never)]
205                 public new int TabIndex {
206                         get { return base.TabIndex; }
207                         set { base.TabIndex = value; }
208                 }
209
210                 [Browsable(false)]
211                 [EditorBrowsable(EditorBrowsableState.Never)]
212                 public new bool TabStop {
213                         get { return base.TabStop; }
214                         set { base.TabStop = value; }
215                 }
216
217                 [Bindable(false)]
218                 [Browsable(false)]
219                 [EditorBrowsable(EditorBrowsableState.Never)]
220                 public override string Text {
221                         get { return base.Text; }
222                         set { base.Text = value; }
223                 }
224
225                 protected override CreateParams CreateParams {
226                         get {
227                                 return base.CreateParams;
228                         }
229                 }
230
231                 protected override ImeMode DefaultImeMode {
232                         get { return base.DefaultImeMode; }
233                 }
234
235                 [Browsable(false)]
236                 [EditorBrowsable(EditorBrowsableState.Never)]
237                 public override Font Font {
238                         get { return base.Font; }
239                         set { base.Font = value; }
240                 }
241
242                 [Browsable(false)]
243                 [EditorBrowsable(EditorBrowsableState.Never)]
244                 public override Color ForeColor {
245                         get { return base.ForeColor; }
246                         set { base.ForeColor = value; }
247                 }
248
249                 [Browsable(false)]
250                 [EditorBrowsable(EditorBrowsableState.Never)]
251                 public override bool AllowDrop {
252                         get { return base.AllowDrop; }
253                         set { base.AllowDrop = value; }
254                 }
255                 #endregion      // Public Properties
256
257                 #region Protected Instance Methods
258                 protected override Size DefaultSize {
259                         get { return ThemeEngine.Current.PictureBoxDefaultSize; }
260                 }
261
262                 protected override void Dispose (bool disposing)
263                 {
264                         if (image != null) {
265                                 StopAnimation ();
266                                 image = null;
267                         }
268 #if NET_2_0
269                         initial_image = null;
270 #endif
271
272                         base.Dispose (disposing);
273                 }
274
275                 protected override void OnPaint (PaintEventArgs pe)
276                 {
277                         ThemeEngine.Current.DrawPictureBox (pe.Graphics, pe.ClipRectangle, this);
278                         base.OnPaint (pe);
279                 }
280
281                 protected override void OnVisibleChanged (EventArgs e)
282                 {
283                         base.OnVisibleChanged (e);
284                 }
285
286                 protected virtual void OnSizeModeChanged (EventArgs e)
287                 {
288                         EventHandler eh = (EventHandler)(Events [SizeModeChangedEvent]);
289                         if (eh != null)
290                                 eh (this, e);
291                 }
292
293                 protected override void OnEnabledChanged (EventArgs e)
294                 {
295                         base.OnEnabledChanged (e);
296                 }
297
298 #if NET_2_0
299                 [EditorBrowsable (EditorBrowsableState.Advanced)]
300                 protected override void OnHandleCreated (EventArgs e)
301                 {
302                         base.OnHandleCreated (e);
303                 }
304
305                 [EditorBrowsable (EditorBrowsableState.Advanced)]
306                 protected override void OnHandleDestroyed (EventArgs e)
307                 {
308                         base.OnHandleDestroyed (e);
309                 }
310                 
311                 protected virtual void OnLoadCompleted (AsyncCompletedEventArgs e)
312                 {
313                         AsyncCompletedEventHandler eh = (AsyncCompletedEventHandler)(Events[LoadCompletedEvent]);
314                         if (eh != null)
315                                 eh (this, e);
316                 }
317                 
318                 protected virtual void OnLoadProgressChanged (ProgressChangedEventArgs e)
319                 {
320                         ProgressChangedEventHandler eh = (ProgressChangedEventHandler)(Events[LoadProgressChangedEvent]);
321                         if (eh != null)
322                                 eh (this, e);
323                 }
324 #endif
325
326                 protected override void OnParentChanged (EventArgs e)
327                 {
328                         base.OnParentChanged (e);
329                 }
330
331                 protected override void OnResize (EventArgs e)
332                 {
333                         base.OnResize (e);
334                         
335                         Invalidate ();
336                 }
337
338 #if NET_2_0
339                 internal override Size GetPreferredSizeCore (Size proposedSize)
340                 {
341                         if (image == null)
342                                 return base.GetPreferredSizeCore (proposedSize);
343                         else
344                                 return image.Size;
345                 }
346 #else
347                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
348                 {
349                         if (size_mode == PictureBoxSizeMode.AutoSize && image != null) {
350                                 width = image.Width;
351                                 height = image.Height;
352                         }
353                         base.SetBoundsCore (x, y, width, height, specified);
354                 }
355 #endif
356                 #endregion      // Protected Instance Methods
357
358 #if NET_2_0
359                 #region ISupportInitialize Interface
360                 void System.ComponentModel.ISupportInitialize.BeginInit() {
361                         no_update++;
362                 }
363
364                 void System.ComponentModel.ISupportInitialize.EndInit() {
365                         if (no_update > 0) {
366                                 no_update--;
367                         }
368                         if (no_update == 0) {
369                                 Invalidate ();
370                         }
371                 }
372                 #endregion      // ISupportInitialize Interface
373 #endif
374
375                 #region Private Properties
376 #if NET_2_0
377                 private WebClient ImageDownload {
378                         get { 
379                                 if (image_download == null)
380                                         image_download = new WebClient ();
381                                         
382                                 return image_download;
383                         }
384                 }
385 #endif
386                 #endregion
387                 
388                 #region Private Methods
389                 private void StopAnimation ()
390                 {
391                         if (frame_handler == null)
392                                 return;
393                         ImageAnimator.StopAnimate (image, frame_handler);
394                         frame_handler = null;
395                 }
396
397                 private void UpdateSize ()
398                 {
399                         if (image == null)
400                                 return;
401 #if NET_2_0
402                         if (Parent != null)
403                                 Parent.PerformLayout (this, "AutoSize");
404 #else
405                         if (size_mode == PictureBoxSizeMode.AutoSize)
406                                 ClientSize = image.Size; 
407 #endif
408                 }
409
410                 private void OnAnimateImage (object sender, EventArgs e)
411                 {
412                         // This is called from a worker thread,BeginInvoke is used
413                         // so the control is updated from the correct thread
414                         
415                         // Check if we have a handle again, since it may have gotten
416                         // destroyed since the last time we checked.
417                         if (!IsHandleCreated)
418                                 return;
419                         
420                         BeginInvoke (new EventHandler (UpdateAnimatedImage), new object [] { this, e });
421                 }
422
423                 private void UpdateAnimatedImage (object sender, EventArgs e)
424                 {
425                         // Check if we have a handle again, since it may have gotten
426                         // destroyed since the last time we checked.
427                         if (!IsHandleCreated)
428                                 return;
429                                 
430                         ImageAnimator.UpdateFrames (image);
431                         Refresh ();
432                 }
433
434                 private void PictureBox_HandleCreated(object sender, EventArgs e) {
435                         UpdateSize ();
436                         if (image != null && ImageAnimator.CanAnimate (image)) {
437                                 frame_handler = new EventHandler (OnAnimateImage);
438                                 ImageAnimator.Animate (image, frame_handler);
439                         }
440                         if (no_update == 0) {
441                                 Invalidate ();
442                         }
443                 }
444                 
445 #if NET_2_0
446                 void ImageDownload_DownloadDataCompleted (object sender, DownloadDataCompletedEventArgs e)
447                 {
448                         if (e.Error != null && !e.Cancelled)
449                                 Image = error_image;
450                         else if (e.Error == null && !e.Cancelled)
451                                 using (MemoryStream ms = new MemoryStream (e.Result))
452                                         Image = Image.FromStream (ms);
453                                         
454                         ImageDownload.DownloadProgressChanged -= new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
455                         ImageDownload.DownloadDataCompleted -= new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
456                         image_download = null;
457                         
458                         OnLoadCompleted (e);
459                 }
460
461                 private void ImageDownload_DownloadProgressChanged (object sender, DownloadProgressChangedEventArgs e)
462                 {
463                         OnLoadProgressChanged (new ProgressChangedEventArgs (e.ProgressPercentage, e.UserState));
464                 }
465 #endif
466                 #endregion      // Private Methods
467
468                 #region Public Instance Methods
469 #if NET_2_0
470                 public void CancelAsync ()
471                 {
472                         if (image_download != null)
473                                 image_download.CancelAsync ();
474                 }
475                 
476                 public void Load ()
477                 {
478                         Load (image_location);
479                 }
480                 
481                 public void Load (string url)
482                 {
483                         if (string.IsNullOrEmpty (url))
484                                 throw new InvalidOperationException ("ImageLocation not specified.");
485                         
486                         image_location = url;
487                         
488                         if (url.Contains ("://"))
489                                 using (Stream s = ImageDownload.OpenRead (url))
490                                         Image = Image.FromStream (s);
491                         else
492                                 Image = Image.FromFile (url);
493                 }
494                 
495                 public void LoadAsync ()
496                 {
497                         LoadAsync (image_location);
498                 }
499                 
500                 public void LoadAsync (string url)
501                 {
502                         // If WaitOnLoad is true, do not do async
503                         if (wait_on_load) {
504                                 Load (url);
505                                 return;
506                         }
507                         image_location = url;
508                         Image = InitialImage;
509                         
510                         if (ImageDownload.IsBusy)
511                                 ImageDownload.CancelAsync ();
512
513                         ImageDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
514                         ImageDownload.DownloadDataCompleted += new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
515                         ImageDownload.DownloadDataAsync (new Uri (url));
516                 }
517 #endif
518                 public override string ToString() {
519                         return String.Format("{0}, SizeMode: {1}", base.ToString (), SizeMode);
520                 }
521                 #endregion
522
523                 #region Events
524                 [Browsable(false)]
525                 [EditorBrowsable(EditorBrowsableState.Never)]
526                 public new event EventHandler CausesValidationChanged {
527                         add { base.CausesValidationChanged += value; }
528                         remove { base.CausesValidationChanged -= value; }
529                 }
530
531                 [Browsable(false)]
532                 [EditorBrowsable(EditorBrowsableState.Never)]
533                 public new event EventHandler Enter {
534                         add { base.Enter += value; }
535                         remove { base.Enter -= value; }
536                 }
537
538                 [Browsable(false)]
539                 [EditorBrowsable(EditorBrowsableState.Never)]
540                 public new event EventHandler FontChanged {
541                         add { base.FontChanged += value; }
542                         remove { base.FontChanged -= value; }
543                 }
544
545                 [Browsable(false)]
546                 [EditorBrowsable(EditorBrowsableState.Never)]
547                 public new event EventHandler ForeColorChanged {
548                         add { base.ForeColorChanged += value; }
549                         remove { base.ForeColorChanged -= value; }
550                 }
551
552                 [Browsable(false)]
553                 [EditorBrowsable(EditorBrowsableState.Never)]
554                 public new event EventHandler ImeModeChanged {
555                         add { base.ImeModeChanged += value; }
556                         remove { base.ImeModeChanged -= value; }
557                 }
558
559                 [Browsable(false)]
560                 [EditorBrowsable(EditorBrowsableState.Never)]
561                 public new event KeyEventHandler KeyDown {
562                         add { base.KeyDown += value; }
563                         remove { base.KeyDown -= value; }
564                 }
565
566                 [Browsable(false)]
567                 [EditorBrowsable(EditorBrowsableState.Never)]
568                 public new event KeyPressEventHandler KeyPress {
569                         add { base.KeyPress += value; }
570                         remove { base.KeyPress -= value; }
571                 }
572
573                 [Browsable(false)]
574                 [EditorBrowsable(EditorBrowsableState.Never)]
575                 public new event KeyEventHandler KeyUp {
576                         add { base.KeyUp += value; }
577                         remove { base.KeyUp -= value; }
578                 }
579
580                 [Browsable(false)]
581                 [EditorBrowsable(EditorBrowsableState.Never)]
582                 public new event EventHandler Leave {
583                         add { base.Leave += value; }
584                         remove { base.Leave -= value; }
585                 }
586
587 #if NET_2_0
588                 static object LoadCompletedEvent = new object ();
589                 static object LoadProgressChangedEvent = new object ();
590
591                 public event AsyncCompletedEventHandler LoadCompleted {
592                         add { Events.AddHandler (LoadCompletedEvent, value); }
593                         remove { Events.RemoveHandler (LoadCompletedEvent, value); }
594                 }
595
596                 public event ProgressChangedEventHandler LoadProgressChanged {
597                         add { Events.AddHandler (LoadProgressChangedEvent, value); }
598                         remove { Events.RemoveHandler (LoadProgressChangedEvent, value); }
599                 }
600 #endif
601
602                 [Browsable(false)]
603                 [EditorBrowsable(EditorBrowsableState.Never)]
604                 public new event EventHandler RightToLeftChanged {
605                         add { base.RightToLeftChanged += value; }
606                         remove { base.RightToLeftChanged -= value; }
607                 }
608
609                 [Browsable(false)]
610                 [EditorBrowsable(EditorBrowsableState.Never)]
611                 public new event EventHandler TabIndexChanged {
612                         add { base.TabIndexChanged += value; }
613                         remove { base.TabIndexChanged -= value; }
614                 }
615
616                 [Browsable(false)]
617                 [EditorBrowsable(EditorBrowsableState.Never)]
618                 public new event EventHandler TabStopChanged {
619                         add { base.TabStopChanged += value; }
620                         remove { base.TabStopChanged -= value; }
621                 }
622
623                 [Browsable(false)]
624                 [EditorBrowsable(EditorBrowsableState.Never)]
625                 public new event EventHandler TextChanged {
626                         add { base.TextChanged += value; }
627                         remove { base.TextChanged -= value; }
628                 }
629
630                 static object SizeModeChangedEvent = new object ();
631                 public event EventHandler SizeModeChanged {
632                         add { Events.AddHandler (SizeModeChangedEvent, value); }
633                         remove { Events.RemoveHandler (SizeModeChangedEvent, value); }
634                 }
635
636                 #endregion      // Events
637         }
638 }
639