- Finished (famous last words)
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / CheckBox.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 //      Dennis Hayes    dennish@raytek.com
24 //      Peter Bartok    pbartok@novell.com
25 //
26 //
27 // $Revision: 1.4 $
28 // $Modtime: $
29 // $Log: CheckBox.cs,v $
30 // Revision 1.4  2004/08/31 18:48:31  pbartok
31 // - Finished (famous last words)
32 //
33 // Revision 1.3  2004/08/30 20:42:26  pbartok
34 // - Implemented CheckBox drawing code
35 //
36 // Revision 1.2  2004/08/30 15:44:20  pbartok
37 // - Updated to fix broken build. Not complete yet.
38 //
39 // Revision 1.1  2004/07/09 05:21:25  pbartok
40 // - Initial check-in
41 //
42 //
43
44 // COMPLETE
45
46 using System;
47 using System.Drawing;
48
49 namespace System.Windows.Forms {
50         public class CheckBox : ButtonBase {
51                 private Appearance              appearance;
52                 private bool                    auto_check;
53                 private ContentAlignment        check_alignment;
54                 private ContentAlignment        text_alignment;
55                 private CheckState              check_state;
56                 private bool                    three_state;
57                 private int                     checkmark_size=13;              // Keep it configurable for accessability
58
59
60                 #region Public Constructors
61                 public CheckBox() {
62                         appearance = Appearance.Normal;
63                         auto_check = true;
64                         check_alignment = ContentAlignment.MiddleLeft;
65
66                         SizeChanged+=new System.EventHandler(RedrawEvent);
67                         TextChanged+=new System.EventHandler(RedrawEvent);
68                 }
69                 #endregion      // Public Constructors
70
71                 #region Public Instance Properties
72                 public Appearance Appearance {
73                         get {
74                                 return appearance;
75                         }
76
77                         set {
78                                 if (value != appearance) {
79                                         value = appearance;
80                                         if (AppearanceChanged != null) {
81                                                 AppearanceChanged(this, EventArgs.Empty);
82                                         }
83                                         CheckRedraw();
84                                         Refresh();
85                                 }
86                         }
87                 }
88
89                 public bool AutoCheck {
90                         get {
91                                 return auto_check;
92                         }
93
94                         set {
95                                 auto_check = value;
96                         }
97                 }
98
99                 public ContentAlignment CheckAlign {
100                         get {
101                                 return check_alignment;
102                         }
103
104                         set {
105                                 if (value != check_alignment) {
106                                         check_alignment = value;
107
108                                         CheckRedraw();
109                                         Refresh();
110                                 }
111                         }
112                 }
113
114                 public bool Checked {
115                         get {
116                                 if (check_state != CheckState.Unchecked) {
117                                         return true;
118                                 }
119                                 return false;
120                         }
121
122                         set {
123                                 if (value && (check_state != CheckState.Checked)) {
124                                         check_state = CheckState.Checked;
125                                         CheckRedraw();
126                                         Refresh();
127                                         OnCheckedChanged(EventArgs.Empty);
128                                 } else if (!value && (check_state != CheckState.Unchecked)) {
129                                         check_state = CheckState.Unchecked;
130                                         CheckRedraw();
131                                         Refresh();
132                                         OnCheckedChanged(EventArgs.Empty);
133                                 }
134                         }
135                 }
136
137                 public CheckState CheckState {
138                         get {
139                                 return check_state;
140                         }
141
142                         set {
143                                 if (value != check_state) {
144                                         bool    was_checked = (check_state != CheckState.Unchecked);
145
146                                         check_state = value;
147
148                                         if (was_checked != (check_state != CheckState.Unchecked)) {
149                                                 OnCheckedChanged(EventArgs.Empty);
150                                         }
151
152                                         OnCheckStateChanged(EventArgs.Empty);
153                                         CheckRedraw();
154                                         Refresh();
155                                 }
156                         }
157                 }
158
159                 public override ContentAlignment TextAlign {
160                         get {
161                                 return text_alignment;
162                         }
163
164                         set {
165                                 if (value != text_alignment) {
166                                         text_alignment = value;
167                                         CheckRedraw();
168                                         Refresh();
169                                 }
170                         }
171                 }
172
173
174                 public bool ThreeState {
175                         get {
176                                 return three_state;
177                         }
178
179                         set {
180                                 three_state = value;
181                         }
182                 }
183                 #endregion      // Public Instance Properties
184
185                 #region Protected Instance Properties
186                 protected override CreateParams CreateParams {
187                         get {
188                                 return base.CreateParams;
189                         }
190                 }
191
192                 protected override Size DefaultSize {
193                         get {
194                                 return new Size(104, 24);
195                         }
196                 }
197                 #endregion      // Protected Instance Properties
198
199                 #region Public Instance Methods
200                 public override string ToString() {
201                         return base.ToString() + ", CheckState: " + (int)check_state;
202                 }
203                 #endregion      // Public Instance Methods
204
205                 #region Protected Instance Methods
206                 protected override AccessibleObject CreateAccessibilityInstance() {
207                         return base.CreateAccessibilityInstance ();
208                 }
209
210                 protected virtual void OnAppearanceChanged(EventArgs e) {
211                         if (AppearanceChanged != null) {
212                                 AppearanceChanged(this, e);
213                         }
214                 }
215
216                 protected virtual void OnCheckedChanged(EventArgs e) {
217                         if (CheckedChanged != null) {
218                                 CheckedChanged(this, e);
219                         }
220                 }
221
222                 protected virtual void OnCheckStateChanged(EventArgs e) {
223                         if (CheckStateChanged != null) {
224                                 CheckStateChanged(this, e);
225                         }
226                 }
227
228                 protected override void OnClick(EventArgs e) {
229                         if (auto_check) {
230                                 switch(check_state) {
231                                         case CheckState.Unchecked: {
232                                                 if (three_state) {
233                                                         CheckState = CheckState.Indeterminate;
234                                                 } else {
235                                                         CheckState = CheckState.Checked;
236                                                 }
237                                                 break;
238                                         }
239
240                                         case CheckState.Indeterminate: {
241                                                 CheckState = CheckState.Checked;
242                                                 break;
243                                         }
244
245                                         case CheckState.Checked: {
246                                                 CheckState = CheckState.Unchecked;
247                                                 break;
248                                         }
249                                 }
250                         }
251                 }
252
253                 protected override void OnHandleCreated(EventArgs e) {
254                         base.OnHandleCreated (e);
255                 }
256
257                 protected override void OnMouseUp(MouseEventArgs e) {
258                         base.OnMouseUp (e);
259                 }
260
261                 protected override bool ProcessMnemonic(char charCode) {
262                         return base.ProcessMnemonic (charCode);
263                 }
264                 #endregion      // Protected Instance Methods
265
266                 #region Events
267                 public event EventHandler       AppearanceChanged;
268                 public event EventHandler       CheckedChanged;
269                 public event EventHandler       CheckStateChanged;
270                 #endregion      // Events
271
272                 #region Internal drawing code
273                 internal override bool CheckRedraw() {\r
274                         this.needs_redraw = true;\r
275 \r
276                         return true;\r
277                 }\r
278 \r
279                 internal override void Redraw() {\r
280                         StringFormat            text_format;
281                         Rectangle               client_rectangle;
282                         Rectangle               text_rectangle;
283                         Rectangle               checkbox_rectangle;
284                         SolidBrush              sb;
285
286                         client_rectangle = ClientRectangle;
287                         text_rectangle = client_rectangle;
288                         checkbox_rectangle = new Rectangle(text_rectangle.X, text_rectangle.Y, checkmark_size, checkmark_size);
289
290                         text_format = new StringFormat();
291                         text_format.Alignment=StringAlignment.Near;
292                         text_format.LineAlignment=StringAlignment.Center;
293
294                         /* Calculate the position of text and checkbox rectangle */
295                         if (appearance!=Appearance.Button) {
296                                 switch(check_alignment) {
297                                         case ContentAlignment.BottomCenter: {
298                                                 if (client_rectangle.Height<checkmark_size*2) {
299                                                         ClientSize=new Size(client_rectangle.Width, checkmark_size*2);
300                                                         client_rectangle = ClientRectangle;
301                                                 }
302                                                 checkbox_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-checkmark_size/2;
303                                                 checkbox_rectangle.Y=client_rectangle.Bottom-checkmark_size;
304                                                 text_rectangle.X=client_rectangle.X;
305                                                 text_rectangle.Width=client_rectangle.Width;
306                                                 break;
307                                         }
308
309                                         case ContentAlignment.BottomLeft: {
310                                                 checkbox_rectangle.X=client_rectangle.Left;
311                                                 checkbox_rectangle.Y=client_rectangle.Bottom-checkmark_size;
312                                                 text_rectangle.X=client_rectangle.X+checkmark_size;
313                                                 text_rectangle.Width=client_rectangle.Width-checkmark_size;
314                                                 break;
315                                         }
316
317                                         case ContentAlignment.BottomRight: {
318                                                 checkbox_rectangle.X=client_rectangle.Right-checkmark_size;
319                                                 checkbox_rectangle.Y=client_rectangle.Bottom-checkmark_size;
320                                                 text_rectangle.X=client_rectangle.X;
321                                                 text_rectangle.Width=client_rectangle.Width-checkmark_size;
322                                                 break;
323                                         }
324
325                                         case ContentAlignment.MiddleCenter: {
326                                                 checkbox_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-checkmark_size/2;
327                                                 checkbox_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-checkmark_size/2;
328                                                 text_rectangle.X=client_rectangle.X;
329                                                 text_rectangle.Width=client_rectangle.Width;
330                                                 break;
331                                         }
332
333                                         default:
334                                         case ContentAlignment.MiddleLeft: {
335                                                 checkbox_rectangle.X=client_rectangle.Left;
336                                                 checkbox_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-checkmark_size/2;
337                                                 text_rectangle.X=client_rectangle.X+checkmark_size;
338                                                 text_rectangle.Width=client_rectangle.Width-checkmark_size;
339                                                 break;
340                                         }
341
342                                         case ContentAlignment.MiddleRight: {
343                                                 checkbox_rectangle.X=client_rectangle.Right-checkmark_size;
344                                                 checkbox_rectangle.Y=(client_rectangle.Bottom-client_rectangle.Top)/2-checkmark_size/2;
345                                                 text_rectangle.X=client_rectangle.X;
346                                                 text_rectangle.Width=client_rectangle.Width-checkmark_size;
347                                                 break;
348                                         }
349
350                                         case ContentAlignment.TopCenter: {
351                                                 if (client_rectangle.Height<checkmark_size*2) {
352                                                         ClientSize=new Size(client_rectangle.Width, checkmark_size*2);
353                                                         client_rectangle = ClientRectangle;
354                                                 }
355                                                 checkbox_rectangle.X=(client_rectangle.Right-client_rectangle.Left)/2-checkmark_size/2;
356                                                 checkbox_rectangle.Y=client_rectangle.Top;
357                                                 text_rectangle.X=client_rectangle.X;
358                                                 text_rectangle.Y=checkmark_size;
359                                                 text_rectangle.Width=client_rectangle.Width;
360                                                 text_rectangle.Height=client_rectangle.Height-checkmark_size;
361                                                 break;
362                                         }
363
364                                         case ContentAlignment.TopLeft: {
365                                                 checkbox_rectangle.X=client_rectangle.Left;
366                                                 checkbox_rectangle.Y=client_rectangle.Top;
367                                                 text_rectangle.X=client_rectangle.X+checkmark_size;
368                                                 text_rectangle.Width=client_rectangle.Width-checkmark_size;
369                                                 break;
370                                         }
371
372                                         case ContentAlignment.TopRight: {
373                                                 checkbox_rectangle.X=client_rectangle.Right-checkmark_size;
374                                                 checkbox_rectangle.Y=client_rectangle.Top;
375                                                 text_rectangle.X=client_rectangle.X;
376                                                 text_rectangle.Width=client_rectangle.Width-checkmark_size;
377                                                 break;
378                                         }
379                                 }
380                         } else {
381                                 text_rectangle.X=client_rectangle.X;
382                                 text_rectangle.Width=client_rectangle.Width;
383                         }
384
385                         /* Set the horizontal alignment of our text */
386                         switch(text_alignment) {
387                                 case ContentAlignment.BottomLeft:
388                                 case ContentAlignment.MiddleLeft:
389                                 case ContentAlignment.TopLeft: {
390                                         text_format.Alignment=StringAlignment.Near;
391                                         break;
392                                 }
393
394                                 case ContentAlignment.BottomCenter:
395                                 case ContentAlignment.MiddleCenter:
396                                 case ContentAlignment.TopCenter: {
397                                         text_format.Alignment=StringAlignment.Center;
398                                         break;
399                                 }
400
401                                 case ContentAlignment.BottomRight:
402                                 case ContentAlignment.MiddleRight:
403                                 case ContentAlignment.TopRight: {
404                                         text_format.Alignment=StringAlignment.Far;
405                                         break;
406                                 }
407                         }
408
409                         /* Set the vertical alignment of our text */
410                         switch(text_alignment) {
411                                 case ContentAlignment.TopLeft: 
412                                 case ContentAlignment.TopCenter: 
413                                 case ContentAlignment.TopRight: {
414                                         text_format.LineAlignment=StringAlignment.Near;
415                                         break;
416                                 }
417
418                                 case ContentAlignment.BottomLeft:
419                                 case ContentAlignment.BottomCenter:
420                                 case ContentAlignment.BottomRight: {
421                                         text_format.LineAlignment=StringAlignment.Far;
422                                         break;
423                                 }
424
425                                 case ContentAlignment.MiddleLeft:
426                                 case ContentAlignment.MiddleCenter:
427                                 case ContentAlignment.MiddleRight: {
428                                         text_format.LineAlignment=StringAlignment.Center;
429                                         break;
430                                 }
431                         }
432
433                         ButtonState state = ButtonState.Normal;
434                         if (FlatStyle == FlatStyle.Flat) {
435                                 state |= ButtonState.Flat;
436                         }
437                         
438                         if (Checked) {
439                                 state |= ButtonState.Checked;
440                         }
441                         
442                         if (ThreeState && (CheckState == CheckState.Indeterminate)) {
443                                 state |= ButtonState.Checked;
444                                 state |= ButtonState.Pushed;
445                         }
446
447                         // Start drawing
448
449                         sb=new SolidBrush(BackColor);
450                         this.DeviceContext.FillRectangle(sb, ClientRectangle);
451                         sb.Dispose();
452
453                         if (appearance!=Appearance.Button) {
454                                 ControlPaint.DrawCheckBox(this.DeviceContext, checkbox_rectangle, state);
455                         } else {
456                                 ControlPaint.DrawButton(this.DeviceContext, text_rectangle, state);
457                         }
458
459                         /* Place the text; to be compatible with Windows place it after the checkbox has been drawn */
460                         sb=new SolidBrush(ForeColor);
461                         this.DeviceContext.DrawString(Text, Font, sb, text_rectangle, text_format);
462                         sb.Dispose();
463
464                         if (Focused) {
465                                 ControlPaint.DrawFocusRectangle(this.DeviceContext, text_rectangle);
466                         }
467                 }\r
468
469                 private void RedrawEvent(object sender, System.EventArgs e) {
470                         CheckRedraw();
471                 }
472                         
473                 #endregion      // Internal drawing code
474         }
475 }