Copied remotely
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / CheckBox.cs
1 //
2 // System.Windows.Forms.CheckBox.cs
3 //
4 // Author:
5 //   stubbed out by Jaak Simm (jaaksimm@firm.ee)
6 //   Dennis Hayes (dennish@Raytek.com)
7 //
8 // (C) Ximian, Inc., 2002
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Drawing;
33
34 namespace System.Windows.Forms {
35
36         /// <summary>
37         /// Represents a Windows check box.
38         /// </summary>
39
40         [MonoTODO]
41         public class CheckBox : ButtonBase {
42
43                 // private fields
44                 Appearance                      appearance;
45                 bool                                    autoCheck;
46                 ContentAlignment        checkAlign;
47                 bool                                    _checked;
48                 CheckState                      checkState;
49                 bool                                    threeState;
50                 ContentAlignment        textAlign;
51                 Rectangle                       textRect;
52                 Rectangle                       checkRect;
53                 StringFormat            textFormat;
54                 int                                     checkMarkSize=13;               // Keep it configurable for accessability
55                 Graphics                                canvasDC;
56                 Bitmap                          canvasBmp;
57                 
58                 // --- Constructor ---
59                 public CheckBox() : base() 
60                 {
61
62                         appearance = Appearance.Normal;
63                         autoCheck = true;
64                         checkAlign = ContentAlignment.MiddleLeft;
65                         _checked = false;
66                         checkState = CheckState.Unchecked;
67                         threeState = false;
68
69                         canvasBmp = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
70                         canvasDC = Graphics.FromImage(canvasBmp);
71
72                         /* Set defaults for drawing text... */
73                         textAlign = ContentAlignment.MiddleLeft;
74                         textFormat = new StringFormat();
75                         textFormat.Alignment=StringAlignment.Near;
76                         textFormat.LineAlignment=StringAlignment.Center;
77                         textRect = ClientRectangle;
78                         textRect.X+=checkMarkSize;
79                         textRect.Width-=checkMarkSize;
80
81                         /* ... and for drawing our checkbox */
82                         checkRect.X=ClientRectangle.Left;
83                         checkRect.Y=(ClientRectangle.Bottom-ClientRectangle.Top)/2-checkMarkSize/2;
84                         checkRect.Width=checkMarkSize;
85                         checkRect.Height=checkMarkSize;
86
87                         SizeChanged+=new System.EventHandler(CheckboxSizeChanged);
88                         GotFocus+=new System.EventHandler(CheckboxUpdate);
89                         LostFocus+=new System.EventHandler(CheckboxUpdate);
90                         TextChanged+=new System.EventHandler(CheckboxUpdate);
91
92                         SubClassWndProc_ = true;
93                         SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
94                         callWinControlProcMask &= ~(CallWinControlProcMask.MOUSE_MESSAGES | CallWinControlProcMask.KEYBOARD_MESSAGES);
95                 }
96                 
97                 // --- CheckBox Properties ---
98                 public Appearance Appearance {
99                         get { return appearance; }
100                         set { appearance=value; }
101                 }
102                 
103                 public bool AutoCheck {
104                         get { return autoCheck; }
105                         set { autoCheck = value; }
106                 }
107                 
108                 public ContentAlignment CheckAlign {
109                         get { return checkAlign; }
110                         set {
111                                 checkAlign=value;
112                                 UpdateCheckbox();
113                         }
114                 }
115                 
116                 public bool Checked {
117                         get { return _checked; }
118                         set { 
119                                 if( _checked != value) {
120                                         CheckState = (value) ? CheckState.Checked : CheckState.Unchecked;
121                                 }
122                         }
123                 }
124                 
125                 public CheckState CheckState {
126                         get { return checkState; }
127                         set { 
128                                 if( checkState != value) {
129
130                                         checkState = value; 
131                                         bool oldChecked = _checked;
132
133                                         if( checkState == CheckState.Unchecked) {
134                                                 _checked = false;
135                                         }
136                                         else {
137                                                 _checked = true;
138                                         }
139
140                                         if( oldChecked != _checked) { 
141                                                 OnCheckedChanged(new EventArgs());
142                                         }
143
144                                         OnCheckStateChanged(new EventArgs());
145                                 }
146                         }
147                 }
148                 
149                 [MonoTODO]
150                 protected override CreateParams CreateParams {
151                         get {
152                                 CreateParams createParams = base.CreateParams;
153         
154                                 createParams.ClassName = "BUTTON";
155
156                                 createParams.Style = (int) (
157                                         (int)WindowStyles.WS_CHILD | 
158                                         (int)WindowStyles.WS_VISIBLE | 
159                                         (int)ButtonStyles.BS_CHECKBOX |
160                                         (int)ButtonStyles.BS_NOTIFY |
161                                         (int)WindowStyles.WS_CLIPSIBLINGS |
162                                         (int)WindowStyles.WS_CLIPCHILDREN |
163                                         (int)WindowStyles.WS_TABSTOP |
164                                         (int)SS_Static_Control_Types.SS_LEFT );
165
166                                 if (autoCheck) {
167                                         createParams.Style |= (int)ButtonStyles.BS_AUTOCHECKBOX;
168                                 }
169
170                                 /* We need this, we draw ourselves */
171                                 createParams.Style |= (int) ButtonStyles.BS_OWNERDRAW;
172
173                                 return createParams;
174                         }
175                 }
176                 
177                 [MonoTODO]
178                 protected override Size DefaultSize {
179                         get { return new Size(100,checkMarkSize); }
180                 }
181                 
182                 [MonoTODO]
183                 public override ContentAlignment TextAlign {
184                         get {
185                                 return textAlign;
186                         }
187                         set {
188                                 textAlign = value;
189                                 UpdateCheckbox();
190                         }
191                 }
192                 
193                 public bool ThreeState {
194                         get {
195                                 return threeState;
196                         }
197
198                         set {
199                                 threeState = value;
200                         }
201                 }       
202                 
203                 // --- CheckBox methods ---
204
205                 protected override AccessibleObject CreateAccessibilityInstance() 
206                 {
207                         throw new NotImplementedException ();
208                 }
209                 
210                 
211                 // [event methods]
212                 [MonoTODO]
213                 protected virtual void OnAppearanceChanged(EventArgs e) 
214                 {
215                         if (AppearanceChanged != null) {
216                                 AppearanceChanged(this, e);
217                         }
218                 }
219                 
220                 [MonoTODO]
221                 protected virtual void OnCheckedChanged(EventArgs e) 
222                 {
223                         //FIXME:
224                         if(CheckedChanged != null) {
225                                 CheckedChanged( this, e);
226                         }
227                 }
228                 
229                 [MonoTODO]
230                 protected virtual void OnCheckStateChanged(EventArgs e) 
231                 {
232                         //FIXME:
233                         if(CheckStateChanged != null) {
234                                 CheckStateChanged( this, e);
235                         }
236                 }
237                 
238                 [MonoTODO]
239                 protected override void OnClick(EventArgs e) 
240                 {
241                         CheckState = (CheckState)Win32.SendMessage(Handle, (int)ButtonMessages.BM_GETCHECK, 0, 0);
242                         base.OnClick(e);
243                 }
244                 
245                 [MonoTODO]
246                 protected override void OnHandleCreated(EventArgs e) 
247                 {
248                         //FIXME:
249                         base.OnHandleCreated(e);
250                         Win32.SendMessage(Handle, (int)ButtonMessages.BM_SETCHECK, (int)checkState, 0);
251                 }
252                 
253 //              protected override void OnMouseDown (MouseEventArgs e) 
254 //              {
255 //                      base.OnMouseDown (e);
256 //              }
257                 
258                 [MonoTODO]
259                 protected override void OnMouseUp(MouseEventArgs mevent) 
260                 {
261                         if (ThreeState) {
262                                 switch (CheckState) {
263                                         case CheckState.Unchecked: {
264                                                 CheckState = CheckState.Checked;
265                                                 break;
266                                         }
267
268                                         case CheckState.Indeterminate: {
269                                                 CheckState = CheckState.Unchecked;
270                                                 break;
271                                         }
272
273                                         case CheckState.Checked: {
274                                                 CheckState = CheckState.Indeterminate;
275                                                 break;
276                                         }
277                                 }
278                         } else {
279                                 Checked = Checked ? false : true;
280                         }
281                         CheckboxRedraw();
282                         Invalidate();
283                         base.OnMouseUp(mevent);
284                 }
285                 // end of [event methods]
286                 
287                 
288                 [MonoTODO]
289                 protected override bool ProcessMnemonic(char charCode) 
290                 {
291                         //FIXME:
292                         return base.ProcessMnemonic(charCode);
293                 }
294                 
295                 [MonoTODO]
296                 //FIXME: do a better tostring
297                 public override string ToString() 
298                 {
299                         if (Checked) {
300                                 return "CheckBox" + " Checked";
301                         } else {
302                                 return "CheckBox" +  " Unchecked";
303                         }
304                 }
305                 
306                 internal override void ButtonPaint (PaintEventArgs e) 
307                 {
308                         if (canvasBmp!=null) {
309                                 e.Graphics.DrawImage(canvasBmp, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
310                         }
311                 }
312                 
313                 /// --- CheckBox events ---
314                 public event EventHandler AppearanceChanged;
315                 public event EventHandler CheckedChanged;
316                 public event EventHandler CheckStateChanged;
317                 
318                 /// --- public class CheckBox.CheckBoxAccessibleObject : AccessibleObject ---
319                 /// the class is only used for .NET framework
320                 /// 
321                 public class CheckBoxAccessibleObject : AccessibleObject {
322                 }
323
324                 private void UpdateCheckbox() {
325                         /* Calculate the position of text and checkbox rectangle */
326                         if (appearance!=Appearance.Button) {
327                                 switch(checkAlign) {
328                                         case ContentAlignment.BottomCenter: {
329                                                 if (ClientRectangle.Height<checkMarkSize*2) {
330                                                         ClientSize=new Size(ClientRectangle.Width, checkMarkSize*2);
331                                                 }
332                                                 checkRect.X=(ClientRectangle.Right-ClientRectangle.Left)/2-checkMarkSize/2;
333                                                 checkRect.Y=ClientRectangle.Bottom-checkMarkSize;
334                                                 textRect.X=ClientRectangle.X;
335                                                 textRect.Width=ClientRectangle.Width;
336                                                 break;
337                                         }
338
339                                         case ContentAlignment.BottomLeft: {
340                                                 checkRect.X=ClientRectangle.Left;
341                                                 checkRect.Y=ClientRectangle.Bottom-checkMarkSize;
342                                                 textRect.X=ClientRectangle.X+checkMarkSize;
343                                                 textRect.Width=ClientRectangle.Width-checkMarkSize;
344                                                 break;
345                                         }
346
347                                         case ContentAlignment.BottomRight: {
348                                                 checkRect.X=ClientRectangle.Right-checkMarkSize;
349                                                 checkRect.Y=ClientRectangle.Bottom-checkMarkSize;
350                                                 textRect.X=ClientRectangle.X;
351                                                 textRect.Width=ClientRectangle.Width-checkMarkSize;
352                                                 break;
353                                         }
354
355                                         case ContentAlignment.MiddleCenter: {
356                                                 checkRect.X=(ClientRectangle.Right-ClientRectangle.Left)/2-checkMarkSize/2;
357                                                 checkRect.Y=(ClientRectangle.Bottom-ClientRectangle.Top)/2-checkMarkSize/2;
358                                                 textRect.X=ClientRectangle.X;
359                                                 textRect.Width=ClientRectangle.Width;
360                                                 break;
361                                         }
362
363                                         default:
364                                         case ContentAlignment.MiddleLeft: {
365                                                 checkRect.X=ClientRectangle.Left;
366                                                 checkRect.Y=(ClientRectangle.Bottom-ClientRectangle.Top)/2-checkMarkSize/2;
367                                                 textRect.X=ClientRectangle.X+checkMarkSize;
368                                                 textRect.Width=ClientRectangle.Width-checkMarkSize;
369                                                 break;
370                                         }
371
372                                         case ContentAlignment.MiddleRight: {
373                                                 checkRect.X=ClientRectangle.Right-checkMarkSize;
374                                                 checkRect.Y=(ClientRectangle.Bottom-ClientRectangle.Top)/2-checkMarkSize/2;
375                                                 textRect.X=ClientRectangle.X;
376                                                 textRect.Width=ClientRectangle.Width-checkMarkSize;
377                                                 break;
378                                         }
379
380                                         case ContentAlignment.TopCenter: {
381                                                 if (ClientRectangle.Height<checkMarkSize*2) {
382                                                         ClientSize=new Size(ClientRectangle.Width, checkMarkSize*2);
383                                                 }
384                                                 checkRect.X=(ClientRectangle.Right-ClientRectangle.Left)/2-checkMarkSize/2;
385                                                 checkRect.Y=ClientRectangle.Top;
386                                                 textRect.X=ClientRectangle.X;
387                                                 textRect.Y=checkMarkSize;
388                                                 textRect.Width=ClientRectangle.Width;
389                                                 textRect.Height=ClientRectangle.Height-checkMarkSize;
390                                                 break;
391                                         }
392
393                                         case ContentAlignment.TopLeft: {
394                                                 checkRect.X=ClientRectangle.Left;
395                                                 checkRect.Y=ClientRectangle.Top;
396                                                 textRect.X=ClientRectangle.X+checkMarkSize;
397                                                 textRect.Width=ClientRectangle.Width-checkMarkSize;
398                                                 break;
399                                         }
400
401                                         case ContentAlignment.TopRight: {
402                                                 checkRect.X=ClientRectangle.Right-checkMarkSize;
403                                                 checkRect.Y=ClientRectangle.Top;
404                                                 textRect.X=ClientRectangle.X;
405                                                 textRect.Width=ClientRectangle.Width-checkMarkSize;
406                                                 break;
407                                         }
408                                 }
409                         } else {
410                                 textRect.X=ClientRectangle.X;
411                                 textRect.Width=ClientRectangle.Width;
412                         }
413
414                         /* Set the horizontal alignment of our text */
415                         switch(textAlign) {
416                                 case ContentAlignment.BottomLeft:
417                                 case ContentAlignment.MiddleLeft:
418                                 case ContentAlignment.TopLeft: {
419                                         textFormat.Alignment=StringAlignment.Near;
420                                         break;
421                                 }
422
423                                 case ContentAlignment.BottomCenter:
424                                 case ContentAlignment.MiddleCenter:
425                                 case ContentAlignment.TopCenter: {
426                                         textFormat.Alignment=StringAlignment.Center;
427                                         break;
428                                 }
429
430                                 case ContentAlignment.BottomRight:
431                                 case ContentAlignment.MiddleRight:
432                                 case ContentAlignment.TopRight: {
433                                         textFormat.Alignment=StringAlignment.Far;
434                                         break;
435                                 }
436                         }
437
438                         /* Set the vertical alignment of our text */
439                         switch(textAlign) {
440                                 case ContentAlignment.TopLeft: 
441                                 case ContentAlignment.TopCenter: 
442                                 case ContentAlignment.TopRight: {
443                                         textFormat.LineAlignment=StringAlignment.Near;
444                                         break;
445                                 }
446
447                                 case ContentAlignment.BottomLeft:
448                                 case ContentAlignment.BottomCenter:
449                                 case ContentAlignment.BottomRight: {
450                                         textFormat.LineAlignment=StringAlignment.Far;
451                                         break;
452                                 }
453
454                                 case ContentAlignment.MiddleLeft:
455                                 case ContentAlignment.MiddleCenter:
456                                 case ContentAlignment.MiddleRight: {
457                                         textFormat.LineAlignment=StringAlignment.Center;
458                                         break;
459                                 }
460                         }
461                         CheckboxRedraw();
462                         Invalidate();
463                 }
464
465                 private void CheckboxRedraw() {
466                         SolidBrush      sb;
467
468                         /* Build the image representing the control */
469
470                         if (canvasDC!=null) {
471                                 canvasDC.Dispose();
472                         }
473                         if (canvasBmp!=null) {
474                                 canvasBmp.Dispose();
475                         }
476
477                         if (ClientRectangle.Width<1 || ClientRectangle.Height<1) {
478                                 return;
479                         }
480                         canvasBmp = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
481                         canvasDC = Graphics.FromImage(canvasBmp);
482
483                         sb=new SolidBrush(BackColor);
484                         canvasDC.FillRectangle(sb, ClientRectangle);
485                         sb.Dispose();
486
487                         ButtonState state = ButtonState.Normal;
488                         if (FlatStyle == FlatStyle.Flat) {
489                                 state |= ButtonState.Flat;
490                         }
491                         
492                         if (Checked) {
493                                 state |= ButtonState.Checked;
494                         }
495                         
496                         if (ThreeState && (CheckState == CheckState.Indeterminate)) {
497                                 state |= ButtonState.ThreeState;
498                         }
499
500                         if (appearance!=Appearance.Button) {
501                                 ControlPaint.DrawCheckBox(canvasDC, checkRect, state);
502                         } else {
503                                 ControlPaint.DrawButton(canvasDC, textRect, state);
504                         }
505
506                         /* Place the text; to be compatible with Windows place it after the checkbox has been drawn */
507                         sb=new SolidBrush(base.foreColor);
508                         canvasDC.DrawString(Text, Font, sb, textRect, textFormat);
509                         sb.Dispose();
510
511                         if (Focused) {
512                                 ControlPaint.DrawFocusRectangle(canvasDC, textRect);
513                         }
514                 }
515
516                 private void CheckboxUpdate(object sender, System.EventArgs e) {
517                         /* Force recalculation of text & checkbox rectangles */
518                         UpdateCheckbox();
519                 }
520
521                 private void CheckboxSizeChanged(object sender, System.EventArgs e)
522                 {
523                         /* Force recalculation of text & checkbox rectangles */
524                         textRect.Y=ClientRectangle.Y;
525                         textRect.Height=ClientRectangle.Height;
526                         UpdateCheckbox();
527                 }
528         }
529
530
531 }