* X11Keyboard.cs: Detect and use the num lock mask.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ButtonBase.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 //      Peter Bartok    pbartok@novell.com
24 //
25 // $Log: ButtonBase.cs,v $
26 // Revision 1.15  2004/10/15 13:32:45  ravindra
27 //      - Renamed Paint() method to Draw() for clarity. Also, moved
28 //      DrawImage() to OnPaint().
29 //
30 // Revision 1.14  2004/10/15 13:16:10  ravindra
31 //      - Redraw () is not virtual now.
32 //      - Added an internal virtual method Paint (), so that
33 //      derived classes can do their painting on their own.
34 //      - Modified OnPaint () to call Paint ().
35 //
36 // Revision 1.13  2004/10/14 06:15:57  ravindra
37 // Redraw () related improvements.
38 //
39 // Revision 1.12  2004/10/13 22:32:38  pbartok
40 // - Now Redraws on MouseUp for FlatStyle Flat and Popup
41 //
42 // Revision 1.11  2004/10/13 20:12:47  pbartok
43 // - Added the Redraw on Resize that got dropped in the last rev
44 //
45 // Revision 1.10  2004/10/05 04:56:11  jackson
46 // Let the base Control handle the buffers, derived classes should not have to CreateBuffers themselves.
47 //
48 // Revision 1.9  2004/09/28 18:44:25  pbartok
49 // - Streamlined Theme interfaces:
50 //   * Each DrawXXX method for a control now is passed the object for the
51 //     control to be drawn in order to allow accessing any state the theme
52 //     might require
53 //
54 //   * ControlPaint methods for the theme now have a CP prefix to avoid
55 //     name clashes with the Draw methods for controls
56 //
57 //   * Every control now retrieves it's DefaultSize from the current theme
58 //
59 // Revision 1.8  2004/09/02 22:24:35  pbartok
60 // - Fixed selection of text color
61 // - Fixed handling of resize event; now properly recreates double buffering
62 //   bitmap
63 // - Added missing assignment of TextAlignment
64 // - Added proper default for TextAlignment
65 //
66 // Revision 1.7  2004/09/01 02:07:37  pbartok
67 // - Enabled display of strings
68 //
69 // Revision 1.6  2004/09/01 01:55:20  pbartok
70 // - Removed the rather odd split between 'needs redraw' and redrawing
71 // - Now handles the events that require regeneration (ambient properties and
72 //   size)
73 //
74 // Revision 1.5  2004/08/31 18:49:58  pbartok
75 // - Removed debug
76 // - Minor fixes
77 //
78 // Revision 1.4  2004/08/30 20:42:10  pbartok
79 // - Made Redraw() and Redraw() virtual
80 // - Improved mouse up/down/move logic to properly track buttons
81 //
82 // Revision 1.3  2004/08/23 23:27:44  pbartok
83 // - Finishing touches. Works now, just needs some optimizations.
84 //
85 // Revision 1.2  2004/08/21 21:57:41  pbartok
86 // - Added loads of debug output for development
87 // - Fixed typo in method name
88 //
89 // Revision 1.1  2004/08/15 21:31:10  pbartok
90 // - First (mostly) working version
91 //
92 //
93 //
94
95 // NOT COMPLETE
96
97 using System.ComponentModel;
98 using System.Drawing;
99 using System.Drawing.Text;
100
101 namespace System.Windows.Forms {
102         public abstract class ButtonBase : Control {
103                 #region Local Variables
104                 internal FlatStyle              flat_style;
105                 internal int                    image_index;
106                 internal Image                  image;
107                 internal ImageList              image_list;
108                 internal ContentAlignment       image_alignment;
109                 internal ContentAlignment       text_alignment;
110                 private ImeMode                 ime_mode;
111                 private bool                    is_default;
112                 internal bool                   has_focus;
113                 internal bool                   is_pressed;
114                 internal bool                   is_entered;
115                 internal bool                   redraw;
116                 internal StringFormat           text_format;
117                 #endregion      // Local Variables
118
119                 #region Private Properties and Methods
120                 internal ButtonState ButtonState {
121                         get {
122                                 ButtonState     ret = ButtonState.Normal;
123
124                                 if (Enabled) {
125                                         // Popup style is only followed as long as the mouse isn't "in" the control
126                                         if (is_entered) {
127                                                 if (flat_style == FlatStyle.Flat) {
128                                                         ret |= ButtonState.Flat;
129                                                 }
130                                         } else {
131                                                 if (flat_style == FlatStyle.Flat || flat_style == FlatStyle.Popup) {
132                                                         ret |= ButtonState.Flat;
133                                                 }
134                                         }
135
136                                         if (is_entered && is_pressed) {
137                                                 ret |= ButtonState.Pushed;
138                                         }
139                                 } else {
140                                         ret |= ButtonState.Inactive;
141                                         if ((flat_style == FlatStyle.Flat) || (flat_style == FlatStyle.Popup)) {
142                                                 ret |= ButtonState.Flat;
143                                         }
144                                 }
145                                 return ret;
146                         }
147                 }
148
149                 [MonoTODO("Make the FillRectangle use a global brush instead of creating one every time")]
150                 internal void Redraw() {
151                         redraw = true;
152                         Refresh ();
153                 }
154
155                 // Derived classes should override Draw method and we dont want
156                 // to break the control signature, hence this approach.
157                 internal virtual void Draw (PaintEventArgs pevent) {
158                         if (redraw) {
159                                 ThemeEngine.Current.DrawButtonBase(this.DeviceContext, pevent.ClipRectangle, this);
160                                 redraw = false;
161                         }
162                 }
163
164                 private void RedrawEvent(object sender, System.EventArgs e) {
165                         Redraw();
166                 }
167
168                 #endregion      // Private Properties and Methods
169
170                 #region Public Constructors
171                 protected ButtonBase() : base() {
172                         flat_style      = FlatStyle.Standard;
173                         image_index     = -1;
174                         image           = null;
175                         image_list      = null;
176                         image_alignment = ContentAlignment.MiddleCenter;
177                         text_alignment  = ContentAlignment.MiddleCenter;
178                         ime_mode        = ImeMode.Inherit;
179                         is_default      = false;
180                         is_entered      = false;
181                         is_pressed      = false;
182                         has_focus       = false;
183                         redraw          = true;
184                         text_format     = new StringFormat();
185                         text_format.Alignment = StringAlignment.Center;
186                         text_format.LineAlignment = StringAlignment.Center;
187                         text_format.HotkeyPrefix = HotkeyPrefix.Show;
188
189                         TextChanged+=new System.EventHandler(RedrawEvent);
190                         ForeColorChanged+=new EventHandler(RedrawEvent);
191                         BackColorChanged+=new System.EventHandler(RedrawEvent);
192                         FontChanged+=new EventHandler(RedrawEvent);
193                         SizeChanged+=new EventHandler(RedrawEvent);
194
195                         SetStyle (ControlStyles.ResizeRedraw, true);
196                 }
197                 #endregion      // Public Constructors
198
199                 #region Public Instance Properties
200                 public FlatStyle FlatStyle {
201                         get {
202                                 return flat_style;
203                         }
204
205                         set { 
206                                 flat_style = value; 
207                                 Redraw();
208                         }
209                 }
210                 
211                 public Image Image {
212                         get {
213                                 return image;
214                         }
215
216                         set { 
217                                 image = value;
218                                 Redraw();
219                         }
220                 }
221
222                 public ContentAlignment ImageAlign {
223                         get {
224                                 return image_alignment;
225                         }
226
227                         set {
228                                 image_alignment=value;
229                                 Redraw();
230                         }
231                 }
232
233                 public int ImageIndex {
234                         get {
235                                 if (image_list==null) {
236                                         return -1;
237                                 }
238                                 return image_index;
239                         }
240
241                         set {
242                                 image_index=value;
243                                 Redraw();
244                         }
245                 }
246
247                 public ImageList ImageList {
248                         get {
249                                 return image_list;
250                         }
251
252                         set {
253                                 if (image_list != null) {
254                                         image_list.Dispose();
255                                 }
256
257                                 image_list = value;
258                                 if (value != null) {
259                                         if (image != null) {
260                                                 image=null;
261                                         }
262                                         if (image_list.Images.Count >= image_index) {
263                                                 image_index=image_list.Images.Count-1;
264                                         }
265                                 }
266                                 Redraw();
267                         }
268                 }
269
270                 public ImeMode ImeMode {
271                         get {
272                                 return ime_mode;
273                         }
274
275                         set {
276                                 ime_mode = value;
277                         }
278                 }
279
280                 public virtual ContentAlignment TextAlign {
281                         get {
282                                 return text_alignment;
283                         }
284
285                         set {
286                                 if (text_alignment != value) {
287                                         text_alignment = value;
288                                         switch(text_alignment) {
289                                                 case ContentAlignment.TopLeft: {
290                                                         text_format.Alignment=StringAlignment.Near;
291                                                         text_format.LineAlignment=StringAlignment.Near;
292                                                         break;
293                                                 }
294
295                                                 case ContentAlignment.TopCenter: {
296                                                         text_format.Alignment=StringAlignment.Center;
297                                                         text_format.LineAlignment=StringAlignment.Near;
298                                                         break;
299                                                 }
300
301                                                 case ContentAlignment.TopRight: {
302                                                         text_format.Alignment=StringAlignment.Far;
303                                                         text_format.LineAlignment=StringAlignment.Near;
304                                                         break;
305                                                 }
306
307                                                 case ContentAlignment.MiddleLeft: {
308                                                         text_format.Alignment=StringAlignment.Near;
309                                                         text_format.LineAlignment=StringAlignment.Center;
310                                                         break;
311                                                 }
312
313                                                 case ContentAlignment.MiddleCenter: {
314                                                         text_format.Alignment=StringAlignment.Center;
315                                                         text_format.LineAlignment=StringAlignment.Center;
316                                                         break;
317                                                 }
318
319                                                 case ContentAlignment.MiddleRight: {
320                                                         text_format.Alignment=StringAlignment.Far;
321                                                         text_format.LineAlignment=StringAlignment.Center;
322                                                         break;
323                                                 }
324
325                                                 case ContentAlignment.BottomLeft: {
326                                                         text_format.Alignment=StringAlignment.Near;
327                                                         text_format.LineAlignment=StringAlignment.Far;
328                                                         break;
329                                                 }
330
331                                                 case ContentAlignment.BottomCenter: {
332                                                         text_format.Alignment=StringAlignment.Center;
333                                                         text_format.LineAlignment=StringAlignment.Far;
334                                                         break;
335                                                 }
336
337                                                 case ContentAlignment.BottomRight: {
338                                                         text_format.Alignment=StringAlignment.Far;
339                                                         text_format.LineAlignment=StringAlignment.Far;
340                                                         break;
341                                                 }
342                                         }       
343                                         Redraw();
344                                 }
345                         }
346                 }
347
348                 #endregion      // Public Instance Properties
349
350                 #region Protected Instance Properties
351                 protected override CreateParams CreateParams {
352                         get { 
353                                 CreateParams    cp;
354
355                                 cp=base.CreateParams;
356
357                                 cp.Style=(int)WindowStyles.WS_VISIBLE | (int)WindowStyles.WS_CHILD;
358
359                                 SetStyle(ControlStyles.UserPaint, true);
360                                 SetStyle(ControlStyles.AllPaintingInWmPaint, true);
361                                 return cp;
362                         }
363                 }
364
365                 protected override ImeMode DefaultImeMode {
366                         get {
367                                 return ImeMode.Inherit;
368                         }
369                 }
370
371                 protected override Size DefaultSize {
372                         get {
373                                 return ThemeEngine.Current.ButtonBaseDefaultSize;
374                         }
375                 }
376
377                 protected bool IsDefault {
378                         get {
379                                 return is_default;
380                         }
381
382                         set {
383                                 if (is_default != value) {
384                                         is_default = true;
385                                         Redraw();
386                                 }
387                         }
388                 }
389                 #endregion      // Public Instance Properties
390
391                 #region Protected Instance Methods
392                 [MonoTODO("Finish setting properties of the AccessibleObject")]
393                 protected override AccessibleObject CreateAccessibilityInstance() {
394                         AccessibleObject ao;
395                         ao=base.CreateAccessibilityInstance();
396                         ao.description="Button";
397
398                         return ao;
399                 }
400
401                 protected override void Dispose(bool Disposing) {
402                         base.Dispose(Disposing);
403                 }
404
405                 protected override void OnEnabledChanged(EventArgs e) {
406                         Redraw();
407                         base.OnEnabledChanged(e);
408                 }
409
410                 protected override void OnGotFocus(EventArgs e) {
411                         has_focus=true;
412                         Redraw();
413                         base.OnGotFocus(e);
414                 }
415
416                 protected override void OnKeyDown(KeyEventArgs kevent) {
417                         if (is_enabled && (kevent.KeyData == Keys.Enter || kevent.KeyData == Keys.Space)) {
418                                 OnClick(EventArgs.Empty);
419                                 kevent.Handled=true;
420                         }
421                         base.OnKeyDown(kevent);
422                 }
423
424                 protected override void OnKeyUp(KeyEventArgs kevent) {
425                         base.OnKeyUp(kevent);
426                 }
427
428                 protected override void OnLostFocus(EventArgs e) {
429                         has_focus=false;
430                         Redraw();
431                         base.OnLostFocus(e);
432                 }
433
434                 protected override void OnMouseDown(MouseEventArgs mevent) {
435                         if (is_enabled && (mevent.Button == MouseButtons.Left)) {
436                                 is_pressed = true;
437                                 this.Capture = true;
438                                 Redraw();
439                         }
440
441                         base.OnMouseDown(mevent);
442                 }
443
444                 protected override void OnMouseEnter(EventArgs e) {
445                         is_entered=true;
446                         if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
447                                 Redraw();
448                         }
449                         base.OnMouseEnter(e);
450                 }
451
452                 protected override void OnMouseLeave(EventArgs e) {
453                         is_entered=false;
454                         if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
455                                 Redraw();
456                         }
457                         base.OnMouseLeave(e);
458                 }
459
460                 protected override void OnMouseMove(MouseEventArgs mevent) {
461                         bool    inside = false;
462                         bool    redraw = false;
463
464                         if (mevent.X>=0 && mevent.Y>=0 && mevent.X<this.client_size.Width && mevent.Y<=this.client_size.Height) {
465                                 inside = true;
466                         }
467
468                         // If the button was pressed and we leave, release the button press and vice versa
469                         if (this.Capture && (inside != is_pressed)) {
470                                 is_pressed = inside;
471                                 redraw = true;
472                         }
473
474                         if (is_entered != inside) {
475                                 is_entered = inside;
476                                 redraw = true;
477                         }
478
479                         if (redraw) {
480                                 Redraw();
481                         }
482
483                         base.OnMouseMove(mevent);
484                 }
485
486                 protected override void OnMouseUp(MouseEventArgs mevent) {
487                         if (this.Capture && mevent.Button == MouseButtons.Left) {
488                                 this.Capture = false;
489                                 if (is_pressed) {
490                                         is_pressed = false;
491                                         Redraw();
492                                 } else if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
493                                         Redraw();
494                                 }
495
496                                 if (mevent.X>=0 && mevent.Y>=0 && mevent.X<this.client_size.Width && mevent.Y<=this.client_size.Height) {
497                                         OnClick(EventArgs.Empty);
498                                 }
499                         }
500                         base.OnMouseUp(mevent);
501                 }
502
503                 protected override void OnPaint(PaintEventArgs pevent) {
504                         Draw (pevent);
505                         pevent.Graphics.DrawImage(this.ImageBuffer, pevent.ClipRectangle, pevent.ClipRectangle, GraphicsUnit.Pixel);
506                         base.OnPaint (pevent);
507                 }
508
509                 protected override void OnParentChanged(EventArgs e) {
510                         base.OnParentChanged(e);
511                 }
512
513                 protected override void OnTextChanged(EventArgs e) {
514                         Redraw();
515                         base.OnTextChanged(e);
516                 }
517
518                 protected override void OnVisibleChanged(EventArgs e) {
519                         if (!Visible) {
520                                 is_pressed = false;
521                                 has_focus = false;
522                                 is_entered = false;
523                         }
524                         base.OnVisibleChanged(e);
525                 }
526
527                 protected void ResetFlagsandPaint() {
528                         // Nothing to do; MS internal
529                         // Should we do Redraw (); ?
530                 }
531
532                 protected override void WndProc(ref Message m) {
533                         base.WndProc(ref m);
534                 }
535                 #endregion      // Public Instance Properties
536         }
537 }