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