* TreeView.cs: Don't draw the selected node when we lose
[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-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Peter Bartok    pbartok@novell.com
24 //
25
26 // COMPLETE
27
28 using System.ComponentModel;
29 using System.ComponentModel.Design;
30 using System.Drawing;
31 using System.Drawing.Text;
32 using System.Runtime.InteropServices;
33
34 namespace System.Windows.Forms {
35         public abstract class ButtonBase : Control {
36                 #region Local Variables
37                 internal FlatStyle              flat_style;
38                 internal int                    image_index;
39                 internal Image                  image;
40                 internal ImageList              image_list;
41                 internal ContentAlignment       image_alignment;
42                 internal ContentAlignment       text_alignment;
43                 private bool                    is_default;
44                 internal bool                   is_pressed;
45                 internal bool                   enter_state;
46                 internal StringFormat           text_format;
47                 #endregion      // Local Variables
48
49                 #region ButtonBaseAccessibleObject sub-class
50                 [ComVisible(true)]
51                 public class ButtonBaseAccessibleObject : ControlAccessibleObject {
52                         #region ButtonBaseAccessibleObject Local Variables
53                         private Control owner;
54                         #endregion      // ButtonBaseAccessibleObject Local Variables
55
56                         #region ButtonBaseAccessibleObject Constructors
57                         public ButtonBaseAccessibleObject(Control owner) : base(owner) {
58                                 this.owner = owner;
59                         }
60                         #endregion      // ButtonBaseAccessibleObject Constructors
61
62                         #region ButtonBaseAccessibleObject Methods
63                         public override void DoDefaultAction() {
64                                 ((ButtonBase)owner).PerformClick();
65                         }
66                         #endregion      // ButtonBaseAccessibleObject Methods
67                 }
68                 #endregion      // ButtonBaseAccessibleObject sub-class
69
70                 #region Private Properties and Methods
71                 internal ButtonState ButtonState {
72                         get {
73                                 ButtonState     ret = ButtonState.Normal;
74
75                                 if (Enabled) {
76                                         // Popup style is only followed as long as the mouse isn't "in" the control
77                                         if (is_entered) {
78                                                 if (flat_style == FlatStyle.Flat) {
79                                                         ret |= ButtonState.Flat;
80                                                 }
81                                         } else {
82                                                 if (flat_style == FlatStyle.Flat || flat_style == FlatStyle.Popup) {
83                                                         ret |= ButtonState.Flat;
84                                                 }
85                                         }
86
87                                         if (is_entered && is_pressed) {
88                                                 ret |= ButtonState.Pushed;
89                                         }
90                                 } else {
91                                         ret |= ButtonState.Inactive;
92                                         if ((flat_style == FlatStyle.Flat) || (flat_style == FlatStyle.Popup)) {
93                                                 ret |= ButtonState.Flat;
94                                         }
95                                 }
96                                 return ret;
97                         }
98                 }
99
100                 [MonoTODO("Make the FillRectangle use a global brush instead of creating one every time")]
101                 internal void Redraw() {
102                         Refresh ();
103                 }
104
105                 // Derived classes should override Draw method and we dont want
106                 // to break the control signature, hence this approach.
107                 internal virtual void Draw (PaintEventArgs pevent) {
108                         ThemeEngine.Current.DrawButtonBase (pevent.Graphics, pevent.ClipRectangle, this);
109                 }
110
111                 internal virtual void HaveDoubleClick() {
112                         // override me
113                 }
114
115                 private void RedrawEvent(object sender, System.EventArgs e) {
116                         Redraw();
117                 }
118
119                 #endregion      // Private Properties and Methods
120
121                 #region Public Constructors
122                 protected ButtonBase() : base() {
123                         flat_style      = FlatStyle.Standard;
124                         image_index     = -1;
125                         image           = null;
126                         image_list      = null;
127                         image_alignment = ContentAlignment.MiddleCenter;
128                         text_alignment  = ContentAlignment.MiddleCenter;
129                         ime_mode        = ImeMode.Inherit;
130                         is_default      = false;
131                         is_entered      = false;
132                         is_pressed      = false;
133                         has_focus       = false;
134                         text_format     = new StringFormat();
135                         text_format.Alignment = StringAlignment.Center;
136                         text_format.LineAlignment = StringAlignment.Center;
137                         text_format.HotkeyPrefix = HotkeyPrefix.Show;
138
139                         TextChanged+=new System.EventHandler(RedrawEvent);
140                         ForeColorChanged+=new EventHandler(RedrawEvent);
141                         BackColorChanged+=new System.EventHandler(RedrawEvent);
142                         FontChanged+=new EventHandler(RedrawEvent);
143                         SizeChanged+=new EventHandler(RedrawEvent);
144
145                         SetStyle(ControlStyles.ResizeRedraw | 
146                                 ControlStyles.Opaque | 
147                                 ControlStyles.UserMouse | 
148                                 ControlStyles.SupportsTransparentBackColor | 
149                                 ControlStyles.CacheText |
150                                 ControlStyles.DoubleBuffer, true);
151                         SetStyle(ControlStyles.StandardClick, false);
152                 }
153                 #endregion      // Public Constructors
154
155                 #region Public Instance Properties
156                 [Localizable(true)]
157                 [DefaultValue(FlatStyle.Standard)]
158                 [MWFDescription("Determines look of button"), MWFCategory("Appearance")]
159                 public FlatStyle FlatStyle {
160                         get {
161                                 return flat_style;
162                         }
163
164                         set {
165                                 flat_style = value;
166                                 Redraw();
167                         }
168                 }
169                 
170                 [Localizable(true)]
171                 [MWFDescription("Sets image to be displayed on button face"), MWFCategory("Appearance")]
172                 public Image Image {
173                         get {
174                                 return image;
175                         }
176
177                         set {
178                                 image = value;
179                                 Redraw();
180                         }
181                 }
182
183                 [Localizable(true)]
184                 [DefaultValue(ContentAlignment.MiddleCenter)]
185                 [MWFDescription("Sets the alignment of the image to be displayed on button face"), MWFCategory("Appearance")]
186                 public ContentAlignment ImageAlign {
187                         get {
188                                 return image_alignment;
189                         }
190
191                         set {
192                                 image_alignment=value;
193                                 Redraw();
194                         }
195                 }
196
197                 [Localizable(true)]
198                 [DefaultValue(-1)]
199                 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
200                 [TypeConverter(typeof(ImageIndexConverter))]
201                 [MWFDescription("Index of image to display, if ImageList is used for button face images"), MWFCategory("Appearance")]
202                 public int ImageIndex {
203                         get {
204                                 if (image_list==null) {
205                                         return -1;
206                                 }
207                                 return image_index;
208                         }
209
210                         set {
211                                 image_index=value;
212                                 Redraw();
213                         }
214                 }
215
216                 [DefaultValue(null)]
217                 [MWFDescription("ImageList used for ImageIndex"), MWFCategory("Appearance")]
218                 public ImageList ImageList {
219                         get {
220                                 return image_list;
221                         }
222
223                         set {
224                                 image_list = value;
225                                 if (value != null) {
226                                         if (image != null) {
227                                                 image=null;
228                                         }
229                                         if (image_list.Images.Count >= image_index) {
230                                                 image_index=image_list.Images.Count-1;
231                                         }
232                                 }
233                                 Redraw();
234                         }
235                 }
236
237                 [Browsable(false)]
238                 [EditorBrowsable (EditorBrowsableState.Never)]
239                 public new ImeMode ImeMode {
240                         get {
241                                 return ime_mode;
242                         }
243
244                         set {
245                                 if (ime_mode != value) {
246                                         ime_mode = value;
247
248                                         if (ImeModeChanged != null) {
249                                                 ImeModeChanged(this, EventArgs.Empty);
250                                         }
251                                 }
252                         }
253                 }
254
255                 [Localizable(true)]
256                 [DefaultValue(ContentAlignment.MiddleCenter)]
257                 [MWFDescription("Alignment for button text"), MWFCategory("Appearance")]
258                 public virtual ContentAlignment TextAlign {
259                         get {
260                                 return text_alignment;
261                         }
262
263                         set {
264                                 if (text_alignment != value) {
265                                         text_alignment = value;
266                                         switch(text_alignment) {
267                                                 case ContentAlignment.TopLeft: {
268                                                         text_format.Alignment=StringAlignment.Near;
269                                                         text_format.LineAlignment=StringAlignment.Near;
270                                                         break;
271                                                 }
272
273                                                 case ContentAlignment.TopCenter: {
274                                                         text_format.Alignment=StringAlignment.Center;
275                                                         text_format.LineAlignment=StringAlignment.Near;
276                                                         break;
277                                                 }
278
279                                                 case ContentAlignment.TopRight: {
280                                                         text_format.Alignment=StringAlignment.Far;
281                                                         text_format.LineAlignment=StringAlignment.Near;
282                                                         break;
283                                                 }
284
285                                                 case ContentAlignment.MiddleLeft: {
286                                                         text_format.Alignment=StringAlignment.Near;
287                                                         text_format.LineAlignment=StringAlignment.Center;
288                                                         break;
289                                                 }
290
291                                                 case ContentAlignment.MiddleCenter: {
292                                                         text_format.Alignment=StringAlignment.Center;
293                                                         text_format.LineAlignment=StringAlignment.Center;
294                                                         break;
295                                                 }
296
297                                                 case ContentAlignment.MiddleRight: {
298                                                         text_format.Alignment=StringAlignment.Far;
299                                                         text_format.LineAlignment=StringAlignment.Center;
300                                                         break;
301                                                 }
302
303                                                 case ContentAlignment.BottomLeft: {
304                                                         text_format.Alignment=StringAlignment.Near;
305                                                         text_format.LineAlignment=StringAlignment.Far;
306                                                         break;
307                                                 }
308
309                                                 case ContentAlignment.BottomCenter: {
310                                                         text_format.Alignment=StringAlignment.Center;
311                                                         text_format.LineAlignment=StringAlignment.Far;
312                                                         break;
313                                                 }
314
315                                                 case ContentAlignment.BottomRight: {
316                                                         text_format.Alignment=StringAlignment.Far;
317                                                         text_format.LineAlignment=StringAlignment.Far;
318                                                         break;
319                                                 }
320                                         }
321                                         Redraw();
322                                 }
323                         }
324                 }
325
326                 #endregion      // Public Instance Properties
327
328                 #region Protected Instance Properties
329                 protected override CreateParams CreateParams {
330                         get {
331                                 CreateParams    cp;
332
333                                 cp=base.CreateParams;
334
335                                 cp.Style=(int)(WindowStyles.WS_VISIBLE | WindowStyles.WS_CHILD | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN);
336
337                                 return cp;
338                         }
339                 }
340
341                 protected override ImeMode DefaultImeMode {
342                         get {
343                                 return ImeMode.Inherit;
344                         }
345                 }
346
347                 protected override Size DefaultSize {
348                         get {
349                                 return ThemeEngine.Current.ButtonBaseDefaultSize;
350                         }
351                 }
352
353                 protected bool IsDefault {
354                         get {
355                                 return is_default;
356                         }
357
358                         set {
359                                 if (is_default != value) {
360                                         is_default = true;
361                                         Redraw();
362                                 }
363                         }
364                 }
365                 #endregion      // Public Instance Properties
366
367                 #region Protected Instance Methods
368                 protected override AccessibleObject CreateAccessibilityInstance() {
369                         AccessibleObject ao;
370                         ao = base.CreateAccessibilityInstance();
371                         ao.description = "Button";
372                         ao.role = AccessibleRole.PushButton;
373
374                         return ao;
375                 }
376
377                 protected override void Dispose(bool Disposing) {
378                         base.Dispose(Disposing);
379                 }
380
381                 protected override void OnEnabledChanged(EventArgs e) {
382                         Redraw();
383                         base.OnEnabledChanged(e);
384                 }
385
386                 protected override void OnGotFocus(EventArgs e) {
387                         has_focus=true;
388                         Redraw();
389                         base.OnGotFocus(e);
390                 }
391
392                 protected override void OnKeyDown(KeyEventArgs kevent) {
393                         if (is_enabled && (kevent.KeyData == Keys.Space)) {
394                                 enter_state = is_entered;
395                                 is_entered = true;
396                                 OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, 2, 2, 0));
397                                 kevent.Handled=true;
398                         }
399                         base.OnKeyDown(kevent);
400                 }
401
402                 protected override void OnKeyUp(KeyEventArgs kevent) {
403                         if (is_enabled && (kevent.KeyData == Keys.Space)) {
404                                 OnMouseUp(new MouseEventArgs(MouseButtons.Left, 1, 2, 2, 0));
405                                 is_entered = enter_state;
406                                 kevent.Handled=true;
407                         }
408                         base.OnKeyUp(kevent);
409                 }
410
411                 protected override void OnLostFocus(EventArgs e) {
412                         has_focus=false;
413                         Redraw();
414                         base.OnLostFocus(e);
415                 }
416
417                 protected override void OnMouseDown(MouseEventArgs mevent) {
418                         if (is_enabled && (mevent.Button == MouseButtons.Left)) {
419                                 is_pressed = true;
420                                 this.Capture = true;
421                                 Redraw();
422                         }
423
424                         base.OnMouseDown(mevent);
425                 }
426
427                 protected override void OnMouseEnter(EventArgs e) {
428                         is_entered=true;
429                         if ( is_enabled )
430                                 Redraw();
431                         base.OnMouseEnter(e);
432                 }
433
434                 protected override void OnMouseLeave(EventArgs e) {
435                         is_entered=false;
436                         if ( is_enabled )
437                                 Redraw();
438                         base.OnMouseLeave(e);
439                 }
440
441                 protected override void OnMouseMove(MouseEventArgs mevent) {
442                         bool    inside = false;
443                         bool    redraw = false;
444
445                         if (mevent.X>=0 && mevent.Y>=0 && mevent.X<this.client_size.Width && mevent.Y<=this.client_size.Height) {
446                                 inside = true;
447                         }
448
449                         // If the button was pressed and we leave, release the button press and vice versa
450                         if (this.Capture && (inside != is_pressed)) {
451                                 is_pressed = inside;
452                                 redraw = true;
453                         }
454
455                         if (is_entered != inside) {
456                                 is_entered = inside;
457                                 redraw = true;
458                         }
459
460                         if (redraw) {
461                                 Redraw();
462                         }
463
464                         base.OnMouseMove(mevent);
465                 }
466
467                 protected override void OnMouseUp(MouseEventArgs mevent) {
468                         if (this.Capture && mevent.Button == MouseButtons.Left) {
469                                 this.Capture = false;
470                                 if (is_pressed) {
471                                         is_pressed = false;
472                                         Redraw();
473                                 } else if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
474                                         Redraw();
475                                 }
476
477                                 if (mevent.X>=0 && mevent.Y>=0 && mevent.X<this.client_size.Width && mevent.Y<=this.client_size.Height) {
478                                         OnClick(EventArgs.Empty);
479                                 }
480                         }
481                         base.OnMouseUp(mevent);
482                 }
483
484                 protected override void OnPaint(PaintEventArgs pevent) {
485                         Draw (pevent);
486                         base.OnPaint (pevent);
487                 }
488
489                 protected override void OnParentChanged(EventArgs e) {
490                         base.OnParentChanged(e);
491                 }
492
493                 protected override void OnTextChanged(EventArgs e) {
494                         Redraw();
495                         base.OnTextChanged(e);
496                 }
497
498                 protected override void OnVisibleChanged(EventArgs e) {
499                         if (!Visible) {
500                                 is_pressed = false;
501                                 has_focus = false;
502                                 is_entered = false;
503                         }
504                         base.OnVisibleChanged(e);
505                 }
506
507                 protected void ResetFlagsandPaint() {
508                         // Nothing to do; MS internal
509                         // Should we do Redraw (); ?
510                 }
511
512                 protected override void WndProc(ref Message m) {
513                         switch((Msg)m.Msg) {
514                                 case Msg.WM_LBUTTONDBLCLK: {
515                                         HaveDoubleClick();
516                                         break;
517                                 }
518
519                                 case Msg.WM_MBUTTONDBLCLK: {
520                                         HaveDoubleClick();
521                                         break;
522                                 }
523
524                                 case Msg.WM_RBUTTONDBLCLK: {
525                                         HaveDoubleClick();
526                                         break;
527                                 }
528                         }
529                         base.WndProc (ref m);
530                 }
531                 #endregion      // Public Instance Properties
532
533
534                 #region Internal Methods
535                 private void PerformClick() {
536                         OnClick(EventArgs.Empty);
537                 }
538                 #endregion      // Internal Methods
539
540                 #region Events
541                 [Browsable(false)]
542                 [EditorBrowsable (EditorBrowsableState.Never)]
543                 public new event EventHandler ImeModeChanged;
544                 #endregion      // Events
545         }
546 }