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