* TreeView.cs: Don't draw the selected node when we lose
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Label.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 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //      Peter Bartok, pbartok@novell.com
25 //
26 //
27
28 // COMPLETE
29
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
32 using System.Drawing;
33 using System.Drawing.Text;
34 using System.Drawing.Imaging;
35 using System.Runtime.InteropServices;
36
37 namespace System.Windows.Forms
38 {
39         [DefaultProperty("Text")]
40         [Designer ("System.Windows.Forms.Design.LabelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
41         public class Label : Control
42         {
43                 private bool autosize;
44                 private Image image;
45                 private bool render_transparent;
46                 private FlatStyle flat_style;
47                 private int preferred_height;
48                 private int preferred_width;
49                 private bool use_mnemonic;
50                 private int image_index = -1;
51                 private ImageList image_list;
52                 internal ContentAlignment image_align;
53                 internal StringFormat string_format;
54                 internal ContentAlignment text_align;                   
55                 static SizeF req_witdthsize = new SizeF (0,0);
56
57                 #region Events
58                 public event EventHandler AutoSizeChanged;
59
60                 [Browsable(false)]
61                 [EditorBrowsable(EditorBrowsableState.Never)]
62                 public new event EventHandler BackgroundImageChanged;
63
64                 [Browsable(false)]
65                 [EditorBrowsable(EditorBrowsableState.Never)]
66                 public new event EventHandler ImeModeChanged;                   
67
68                 [Browsable(false)]
69                 [EditorBrowsable(EditorBrowsableState.Never)]
70                 public new event KeyEventHandler KeyDown;               
71
72                 [Browsable(false)]
73                 [EditorBrowsable(EditorBrowsableState.Never)]
74                 public new event KeyPressEventHandler KeyPress;         
75
76                 [Browsable(false)]
77                 [EditorBrowsable(EditorBrowsableState.Never)]
78                 public new event KeyEventHandler KeyUp;
79
80                 [Browsable(false)]
81                 [EditorBrowsable(EditorBrowsableState.Never)]
82                 public new event EventHandler TabStopChanged;
83
84                 public event EventHandler TextAlignChanged;
85                 #endregion
86
87                 public Label ()
88                 {
89                         // Defaults in the Spec
90                         autosize = false;
91                         string_format = new StringFormat();
92                         TextAlign = ContentAlignment.TopLeft;
93                         image = null;
94                         UseMnemonic = true;
95                         image_list = null;
96                         image_align = ContentAlignment.MiddleCenter;
97                         SetUseMnemonic (UseMnemonic);
98                         flat_style = FlatStyle.Standard;
99
100                         CalcPreferredHeight ();
101                         CalcPreferredWidth ();
102
103                         AutoSizeChanged = null;
104                         TextAlignChanged = null;
105
106                         SetStyle (ControlStyles.Selectable, false);
107                         SetStyle (ControlStyles.ResizeRedraw | 
108                                 ControlStyles.UserPaint | 
109                                 ControlStyles.AllPaintingInWmPaint |
110                                 ControlStyles.SupportsTransparentBackColor |
111                                 ControlStyles.DoubleBuffer, true);
112                         
113                         HandleCreated += new EventHandler (OnHandleCreatedLB);
114                 }
115
116                 #region Public Properties
117                 [DefaultValue(false)]
118                 [Localizable(true)]
119                 [RefreshProperties(RefreshProperties.All)]
120                 public virtual bool AutoSize {
121                         get { return autosize; }
122                         set {
123                                 if (autosize == value)
124                                         return;
125
126                                 autosize = value;
127                                 CalcAutoSize ();
128                                 Refresh ();
129
130                                 OnAutoSizeChanged (new EventArgs ());                                   
131                         }
132                 }
133
134                 [Browsable(false)]
135                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
136                 [EditorBrowsable(EditorBrowsableState.Never)]
137                 public override Image BackgroundImage {
138                         get {
139                                 return base.BackgroundImage;
140                         }
141                         set {
142                                 if (base.BackgroundImage == value)
143                                         return;
144
145                                 if (BackgroundImageChanged != null)
146                                         BackgroundImageChanged (this, EventArgs.Empty);
147
148                                 base.BackgroundImage = value;
149                                 Refresh ();
150                         }
151                 }
152
153                 [DefaultValue(BorderStyle.None)]
154                 [DispId(-504)]
155                 public virtual BorderStyle BorderStyle {
156                         get { return InternalBorderStyle; }
157                         set { InternalBorderStyle = value; }
158                 }
159
160                 protected override CreateParams CreateParams {
161                         get { return base.CreateParams;}
162                 }
163
164                 protected override ImeMode DefaultImeMode {
165                         get { return ImeMode.Disable;}
166                 }
167
168                 protected override Size DefaultSize {
169                         get {return ThemeEngine.Current.LabelDefaultSize;}
170                 }
171
172                 [DefaultValue(FlatStyle.Standard)]
173                 public FlatStyle FlatStyle {
174                         get {
175                                 return flat_style;
176                         }
177                         set {
178                                 if (!Enum.IsDefined (typeof (FlatStyle), value))
179                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for FlatStyle", value));
180
181                                 if (flat_style == value)
182                                         return;
183
184                                 flat_style = value;
185                                 Refresh ();
186                         }
187                 }
188
189                 [Localizable(true)]
190                 public Image Image {
191                         get {
192                                 if (image != null) {
193                                         return image;
194                                 }
195                                 
196                                 if (image_list != null && ImageIndex >= 0) {
197                                         return image_list.Images[ImageIndex];
198                                 }
199                                 
200                                 return null;
201                         }
202                         set {
203                                 if (image == value)
204                                         return;
205
206                                 image = value;
207                                 Refresh ();
208                         }
209                 }
210
211                 [DefaultValue(ContentAlignment.MiddleCenter)]
212                 [Localizable(true)]
213                 public ContentAlignment ImageAlign {
214                         get {
215                                 return image_align;
216                         }
217                         set {
218                                 if (!Enum.IsDefined (typeof (ContentAlignment), value))
219                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ContentAlignment", value));
220
221                                 if (image_align == value)
222                                         return;
223
224                                 image_align = value;
225                                 Refresh ();
226                         }
227                 }
228
229                 [DefaultValue (-1)]
230                 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
231                 [Localizable (true)]
232                 [TypeConverter (typeof (ImageIndexConverter))]
233                 public int ImageIndex {
234                         get { 
235                                 if (ImageList == null) {
236                                         return -1;
237                                 }
238                                 
239                                 if (image_index >= image_list.Images.Count) {
240                                         return image_list.Images.Count - 1;
241                                 }
242                                 
243                                 return image_index;
244                         }
245                         set {
246
247                                 if (value < -1)
248                                         throw new ArgumentException ();
249
250                                 if (image_index == value)
251                                         return;
252
253                                 image_index = value;
254
255                                 if (ImageList != null && image_index !=-1)
256                                         Image = null;
257
258                                 Refresh ();
259                         }
260                 }
261
262                 [DefaultValue(null)]
263                 public ImageList ImageList {
264                         get { return image_list;}
265                         set {
266                                 if (image_list == value)
267                                         return;
268                                         
269                                 image_list = value;
270
271                                 if (image_list != null && image_index !=-1)
272                                         Image = null;
273
274                                 Refresh ();
275                         }
276                 }
277
278                 [Browsable(false)]
279                 [EditorBrowsable(EditorBrowsableState.Never)]
280                 public new ImeMode ImeMode {
281                         get { return base.ImeMode; }
282                         set {
283                                 if (value == ImeMode)
284                                         return;
285                                 base.ImeMode = value;
286                                 if (ImeModeChanged != null)
287                                         ImeModeChanged (this, EventArgs.Empty);
288                         }
289                 }
290
291                 [Browsable(false)]
292                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
293                 [EditorBrowsable(EditorBrowsableState.Advanced)]
294                 public virtual int PreferredHeight {
295                         get { return preferred_height; }
296                 }
297
298                 [Browsable(false)]
299                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
300                 [EditorBrowsable(EditorBrowsableState.Advanced)]
301                 public virtual int PreferredWidth {
302                         get {return preferred_width; }
303                 }
304
305                 protected virtual bool RenderTransparent {
306                         get { return render_transparent; }
307                         set { render_transparent = value;}
308                 }
309                 
310                 [Browsable(false)]
311                 [DefaultValue(false)]
312                 [EditorBrowsable(EditorBrowsableState.Never)]
313                 public new bool TabStop  {
314                         get { return base.TabStop; }
315                         set {
316                                 if (value == base.TabStop)
317                                         return;
318
319                                 base.TabStop = value;
320                                 if (TabStopChanged != null)
321                                         TabStopChanged (this, EventArgs.Empty);
322                         }
323                 }
324
325                 [DefaultValue(ContentAlignment.TopLeft)]
326                 [Localizable(true)]
327                 public virtual ContentAlignment TextAlign {
328                         get { return text_align; }
329
330                         set {
331                                 if (!Enum.IsDefined (typeof (ContentAlignment), value))
332                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ContentAlignment", value));
333
334                                 if (text_align != value) {
335
336                                         text_align = value;
337
338                                         switch (value) {
339
340                                         case ContentAlignment.BottomLeft:
341                                                 string_format.LineAlignment = StringAlignment.Far;
342                                                 string_format.Alignment = StringAlignment.Near;
343                                                 break;
344                                         case ContentAlignment.BottomCenter:
345                                                 string_format.LineAlignment = StringAlignment.Far;
346                                                 string_format.Alignment = StringAlignment.Center;
347                                                 break;
348                                         case ContentAlignment.BottomRight:
349                                                 string_format.LineAlignment = StringAlignment.Far;
350                                                 string_format.Alignment = StringAlignment.Far;
351                                                 break;
352                                         case ContentAlignment.TopLeft:
353                                                 string_format.LineAlignment = StringAlignment.Near;
354                                                 string_format.Alignment = StringAlignment.Near;
355                                                 break;
356                                         case ContentAlignment.TopCenter:
357                                                 string_format.LineAlignment = StringAlignment.Near;
358                                                 string_format.Alignment = StringAlignment.Center;
359                                                 break;
360                                         case ContentAlignment.TopRight:
361                                                 string_format.LineAlignment = StringAlignment.Near;
362                                                 string_format.Alignment = StringAlignment.Far;
363                                                 break;
364                                         case ContentAlignment.MiddleLeft:
365                                                 string_format.LineAlignment = StringAlignment.Center;
366                                                 string_format.Alignment = StringAlignment.Near;
367                                                 break;
368                                         case ContentAlignment.MiddleRight:
369                                                 string_format.LineAlignment = StringAlignment.Center;
370                                                 string_format.Alignment = StringAlignment.Far;
371                                                 break;
372                                         case ContentAlignment.MiddleCenter:
373                                                 string_format.LineAlignment = StringAlignment.Center;
374                                                 string_format.Alignment = StringAlignment.Center;
375                                                 break;
376                                         default:
377                                                 break;
378                                         }
379
380                                         OnTextAlignChanged (new EventArgs ());
381                                         Refresh();
382                                 }
383                         }
384                 }
385
386                 [DefaultValue(true)]
387                 public bool UseMnemonic {
388                         get { return use_mnemonic; }
389                         set {
390                                 if (use_mnemonic != value) {
391                                         use_mnemonic = value;
392                                         SetUseMnemonic (use_mnemonic);
393                                         Refresh ();
394                                 }
395                         }
396                 }
397
398                 #endregion
399
400
401                 #region Public Methods
402
403                 protected Rectangle CalcImageRenderBounds (Image image, Rectangle area, ContentAlignment img_align)
404                 {
405                         Rectangle rcImageClip = area;
406                         rcImageClip.Inflate (-2,-2);
407
408                         int X = area.X;
409                         int Y = area.Y;
410
411                         if (img_align == ContentAlignment.TopCenter ||
412                                 img_align == ContentAlignment.MiddleCenter ||
413                                 img_align == ContentAlignment.BottomCenter) {
414                                 X += (area.Width - image.Width) / 2;
415                         }
416                         else if (img_align == ContentAlignment.TopRight ||
417                                 img_align == ContentAlignment.MiddleRight||
418                                 img_align == ContentAlignment.BottomRight) {
419                                 X += (area.Width - image.Width);
420                         }
421
422                         if( img_align == ContentAlignment.BottomCenter ||
423                                 img_align == ContentAlignment.BottomLeft ||
424                                 img_align == ContentAlignment.BottomRight) {
425                                 Y += area.Height - image.Height;
426                         }
427                         else if(img_align == ContentAlignment.MiddleCenter ||
428                                         img_align == ContentAlignment.MiddleLeft ||
429                                         img_align == ContentAlignment.MiddleRight) {
430                                 Y += (area.Height - image.Height) / 2;
431                         }
432
433                         rcImageClip.X = X;
434                         rcImageClip.Y = Y;
435                         rcImageClip.Width = image.Width;
436                         rcImageClip.Height = image.Height;
437
438                         return rcImageClip;
439                 }
440
441                 
442                 protected override AccessibleObject CreateAccessibilityInstance ()
443                 {
444                         return base.CreateAccessibilityInstance ();
445                 }
446
447                 protected override void Dispose(bool disposing)
448                 {
449                         base.Dispose (disposing);
450
451                         if (disposing)
452                                 string_format.Dispose ();
453                 }
454
455                 protected void DrawImage (Graphics g, Image image, Rectangle area, ContentAlignment img_align)
456                 {
457                         if (image == null || g == null)
458                                 return;
459
460                         Rectangle rcImageClip = CalcImageRenderBounds (image, area, img_align);
461
462                         if (Enabled)
463                                 g.DrawImage (image, rcImageClip.X, rcImageClip.Y, rcImageClip.Width, rcImageClip.Height);
464                         else
465                                 ControlPaint.DrawImageDisabled (g, image, rcImageClip.X, rcImageClip.Y, BackColor);
466                 }
467
468                 protected virtual void OnAutoSizeChanged (EventArgs e)
469                 {
470                         if (AutoSizeChanged != null)
471                                 AutoSizeChanged (this, e);
472                 }
473
474                 protected override void OnEnabledChanged (EventArgs e)
475                 {
476                         base.OnEnabledChanged (e);
477                 }
478
479                 protected override void OnFontChanged (EventArgs e)
480                 {
481                         base.OnFontChanged (e);
482                         if (autosize) {
483                                 CalcAutoSize();
484                         } else {
485                                 CalcPreferredHeight ();
486                         }
487                         Refresh ();
488                 }
489
490                 protected override void OnPaint (PaintEventArgs pevent)
491                 {
492                         ThemeEngine.Current.DrawLabel (pevent.Graphics, ClientRectangle, this);
493                         DrawImage (pevent.Graphics, Image, ClientRectangle, image_align);
494                         base.OnPaint(pevent);
495                 }
496
497                 protected override void OnParentChanged (EventArgs e)
498                 {
499                         base.OnParentChanged (e);
500                 }
501
502                 protected virtual void OnTextAlignChanged (EventArgs e)
503                 {
504                         if (TextAlignChanged != null)
505                                 TextAlignChanged (this, e);
506                 }
507
508                 protected override void OnTextChanged (EventArgs e)
509                 {
510                         base.OnTextChanged (e);                 
511                         if (autosize) {
512                                 CalcAutoSize ();
513                         } else {
514                                 CalcPreferredWidth ();
515                         }
516                         Refresh ();
517                 }
518
519                 protected override void OnVisibleChanged (EventArgs e)
520                 {
521                         base.OnVisibleChanged (e);
522                 }
523
524                 protected override bool ProcessMnemonic (char charCode)
525                 {
526                         if (IsMnemonic(charCode, Text) == true) {
527                                 // Select item next in line in tab order
528                                 if (this.parent != null) {
529                                         parent.SelectNextControl(this, true, false, false, false);
530                                 }
531                                 return true;
532                         }
533                         
534                         return base.ProcessMnemonic (charCode);
535                 }
536
537                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
538                 {
539                         base.SetBoundsCore (x, y, width, height, specified);
540                 }
541
542                 public override string ToString()
543                 {
544                         return base.ToString () + ", Text: " + Text;
545                 }
546
547                 protected override void WndProc (ref Message m)
548                 {
549                         switch ((Msg) m.Msg) {
550                                 case Msg.WM_DRAWITEM: {
551                                         m.Result = (IntPtr)1;
552                                 }
553                                         break;
554                                 default:
555                                         base.WndProc (ref m);
556                                         break;
557                         }
558                 }
559
560                 #endregion Public Methods
561
562                 #region Private Methods
563
564                 private void CalcAutoSize ()
565                 {
566                         if (IsHandleCreated == false || AutoSize == false)
567                                 return;
568
569                         CalcPreferredWidth ();
570                         CalcPreferredHeight ();
571
572                         Width =  PreferredWidth;
573                         Height =  PreferredHeight;                      
574                 }
575
576                 private void CalcPreferredHeight ()
577                 {
578                         preferred_height = Font.Height;
579
580                         switch (border_style) {
581                         case BorderStyle.None:
582                                 preferred_height += 3;
583                                 break;
584                         case BorderStyle.FixedSingle:
585                         case BorderStyle.Fixed3D:
586                                 preferred_height += 6;
587                                 break;
588                         default:
589                                 break;
590                         }
591
592                 }
593
594                 private void CalcPreferredWidth ()
595                 {
596                         SizeF size;
597                         size = DeviceContext.MeasureString (Text, Font, req_witdthsize, string_format);
598                         preferred_width = (int) size.Width + 3;
599                 }
600
601                 private void OnHandleCreatedLB (Object o, EventArgs e)
602                 {
603                         if (autosize)
604                                 CalcAutoSize ();
605                 }
606
607                 private void SetUseMnemonic (bool use)
608                 {
609                         if (use)
610                                 string_format.HotkeyPrefix = HotkeyPrefix.Show;
611                         else
612                                 string_format.HotkeyPrefix = HotkeyPrefix.None;
613                 }
614
615                 #endregion Private Methods
616
617         }
618 }