Merge pull request #3802 from lambdageek/dev-reference-attr-take3
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / RadioButton.cs
index 36ed2692fd1b64fe13d36795fb981be31708e383..4290a1e262057ce0120f4efa20f4bb4f83e10af1 100644 (file)
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-// System.Windows.Forms.RadioButton.cs
+// Copyright (c) 2004-2005 Novell, Inc.
 //
-// Author:
-//   stubbed out by Daniel Carrera (dcarrera@math.toronto.edu)
-//     Dennis Hayes (dennish@raytek.com)
-//   implemented by Aleksey Ryabchuk (ryabchuk@yahoo.com)
-// (C) 2002/3 Ximian, Inc
+// Authors:
+//     Peter Bartok    pbartok@novell.com
 //
-using System.Drawing;
+
 using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Text;
+using System.Runtime.InteropServices;
 
 namespace System.Windows.Forms {
+       [DefaultProperty("Checked")]
+       [DefaultEvent("CheckedChanged")]
+       [ClassInterface (ClassInterfaceType.AutoDispatch)]
+       [ComVisible (true)]
+       [DefaultBindingProperty ("Checked")]
+       [ToolboxItem ("System.Windows.Forms.Design.AutoSizeToolboxItem," + Consts.AssemblySystem_Design)]
+       [Designer ("System.Windows.Forms.Design.RadioButtonDesigner, " + Consts.AssemblySystem_Design)]
+       public class RadioButton : ButtonBase {
+               #region Local Variables
+               internal Appearance             appearance;
+               internal bool                   auto_check;
+               internal ContentAlignment       radiobutton_alignment;
+               internal CheckState             check_state;
+               #endregion      // Local Variables
+
+               #region RadioButtonAccessibleObject Subclass
+               [ComVisible(true)]
+               public class RadioButtonAccessibleObject : ButtonBaseAccessibleObject {
+                       #region RadioButtonAccessibleObject Local Variables
+                       private new RadioButton owner;
+                       #endregion      // RadioButtonAccessibleObject Local Variables
+
+                       #region RadioButtonAccessibleObject Constructors
+                       public RadioButtonAccessibleObject(RadioButton owner) : base(owner) {
+                               this.owner = owner;
+                       }
+                       #endregion      // RadioButtonAccessibleObject Constructors
+
+                       #region RadioButtonAccessibleObject Properties
+                       public override string DefaultAction {
+                               get {
+                                       return "Select";
+                               }
+                       }
+
+                       public override AccessibleRole Role {
+                               get {
+                                       return AccessibleRole.RadioButton;
+                               }
+                       }
 
-       // <summary>
-       // Represents a Windows radio button
-       // </summary>
+                       public override AccessibleStates State {
+                               get {
+                                       AccessibleStates        retval;
 
-    public class RadioButton : ButtonBase {
+                                       retval = AccessibleStates.Default;
 
-               Appearance appearance;
-               bool       autoCheck;
-               ContentAlignment checkAlign;
-               bool       checked_;
+                                       if (owner.check_state == CheckState.Checked) {
+                                               retval |= AccessibleStates.Checked;
+                                       }
 
-               public RadioButton()
-               {
+                                       if (owner.Focused) {
+                                               retval |= AccessibleStates.Focused;
+                                       }
+
+                                       if (owner.CanFocus) {
+                                               retval |= AccessibleStates.Focusable;
+                                       }
+
+                                       return retval;
+                               }
+                       }
+                       #endregion      // RadioButtonAccessibleObject Properties
+
+                       #region RadioButtonAccessibleObject Methods
+                       public override void DoDefaultAction() {
+                               owner.PerformClick();
+                       }
+                       #endregion      // RadioButtonAccessibleObject Methods
+               }
+               #endregion      // RadioButtonAccessibleObject Sub-class
+
+               #region Public Constructors
+               public RadioButton() {
                        appearance = Appearance.Normal;
-                       autoCheck  = true;
-                       checkAlign = ContentAlignment.MiddleLeft;
-                       checked_   = false;
+                       auto_check = true;
+                       radiobutton_alignment = ContentAlignment.MiddleLeft;
+                       TextAlign = ContentAlignment.MiddleLeft;
+                       TabStop = false;
                }
+               #endregion      // Public Constructors
+
+               #region Private Methods
+
+               // When getting OnEnter we need to set Checked as true in case none of the sibling radio
+               // buttons is checked.
+               private void PerformDefaultCheck ()
+               {
+                       // if we are already checked, no need to check the other controls
+                       if (!auto_check || Checked)
+                               return;
+
+                       bool is_any_selected = false;
+                       Control c = Parent;
+                       if (c != null) {
+                               for (int i = 0; i < c.Controls.Count; i++) {
+                                       RadioButton rb = c.Controls [i] as RadioButton;
+                                       if (rb == null || !rb.auto_check)
+                                               continue;
+
+                                       if (rb.check_state == CheckState.Checked) {
+                                               is_any_selected = true;
+                                               break;
+                                       }
+                               }
+                       }
 
+                       if (!is_any_selected)
+                               Checked = true;
+               }
+
+               private void UpdateSiblings() {
+                       Control c;
+
+                       if (auto_check == false) {
+                               return;
+                       }
+
+                       // Remove tabstop property from and uncheck our radio-button siblings
+                       c = this.Parent;
+                       if (c != null) {
+                               for (int i = 0; i < c.Controls.Count; i++) {
+                                       if ((this != c.Controls[i]) && (c.Controls[i] is RadioButton)) {
+                                               if (((RadioButton)(c.Controls[i])).auto_check) {
+                                                       c.Controls[i].TabStop = false;
+                                                       ((RadioButton)(c.Controls[i])).Checked = false;
+                                               }
+                                       }
+                               }
+                       }
+
+                       this.TabStop = true;
+               }
+
+               internal override void Draw (PaintEventArgs pe) {
+                       // FIXME: This should be called every time something that can affect it
+                       // is changed, not every paint.  Can only change so many things at a time.
+
+                       // Figure out where our text and image should go
+                       Rectangle glyph_rectangle;
+                       Rectangle text_rectangle;
+                       Rectangle image_rectangle;
+
+                       ThemeEngine.Current.CalculateRadioButtonTextAndImageLayout (this, Point.Empty, out glyph_rectangle, out text_rectangle, out image_rectangle);
+
+                       // Draw our button
+                       if (FlatStyle != FlatStyle.System && Appearance != Appearance.Button)
+                               ThemeEngine.Current.DrawRadioButton (pe.Graphics, this, glyph_rectangle, text_rectangle, image_rectangle, pe.ClipRectangle);
+                       else
+                               ThemeEngine.Current.DrawRadioButton (pe.Graphics, this.ClientRectangle, this);
+               }
+
+               internal override Size GetPreferredSizeCore (Size proposedSize)
+               {
+                       if (this.AutoSize)
+                               return ThemeEngine.Current.CalculateRadioButtonAutoSize (this);
+
+                       return base.GetPreferredSizeCore (proposedSize);
+               }
+               #endregion      // Private Methods
+
+               #region Public Instance Properties
+               [DefaultValue(Appearance.Normal)]
+               [Localizable(true)]
                public Appearance Appearance {
-                       get {   return appearance; }
-                       set {
-                               if ( !Enum.IsDefined ( typeof(Appearance), value ) )
-                                       throw new InvalidEnumArgumentException( "Appearance",
-                                               (int)value,
-                                               typeof(Appearance));
+                       get {
+                               return appearance;
+                       }
 
-                               if ( appearance != value ) {
-                                       int oldStyle = AppearanceStyle;
+                       set {
+                               if (value != appearance) {
                                        appearance = value;
-                                       
-                                       if ( IsHandleCreated )
-                                               Win32.UpdateWindowStyle ( Handle, oldStyle, AppearanceStyle );
-
-                                       if ( AppearanceChanged != null )
-                                               AppearanceChanged ( this, EventArgs.Empty );
+                                       EventHandler eh = (EventHandler)(Events [AppearanceChangedEvent]);
+                                       if (eh != null)
+                                               eh (this, EventArgs.Empty);
+                                       if (Parent != null)
+                                               Parent.PerformLayout (this, "Appearance");
+                                       Invalidate();
                                }
                        }
                }
 
+               [DefaultValue(true)]
                public bool AutoCheck {
-                       get {   return autoCheck; }
-                       set {
-                               if ( autoCheck != value ) {
-                                       int oldStyle = AutoCheckStyle;
-                                       autoCheck = value;
+                       get {
+                               return auto_check;
+                       }
 
-                                       if ( IsHandleCreated )
-                                               Win32.UpdateWindowStyle ( Handle, oldStyle, AutoCheckStyle );
-                               }
+                       set {
+                               auto_check = value;
                        }
                }
 
-               [MonoTODO]
+               [Localizable(true)]
+               [DefaultValue(ContentAlignment.MiddleLeft)]
                public ContentAlignment CheckAlign {
-                       get {   return checkAlign; }
+                       get {
+                               return radiobutton_alignment;
+                       }
+
                        set {
-                               if ( !Enum.IsDefined ( typeof(ContentAlignment), value ) )
-                                       throw new InvalidEnumArgumentException( "CheckAlign",
-                                               (int)value,
-                                               typeof(Appearance));
+                               if (value != radiobutton_alignment) {
+                                       radiobutton_alignment = value;
 
-                               if ( checkAlign != value ) {
-                                       checkAlign = value;
+                                       Invalidate();
                                }
                        }
                }
 
+               [DefaultValue(false)]
+               [SettingsBindable (true)]
+               [Bindable (true, BindingDirection.OneWay)]
                public bool Checked {
-                       get {   return checked_; }
-                       set {
-                               if ( checked_ != value ) {
-                                       checked_ = value;
-
-                                       updateCheck ( );
-                                       OnCheckedChanged ( EventArgs.Empty );
+                       get {
+                               if (check_state != CheckState.Unchecked) {
+                                       return true;
                                }
+                               return false;
                        }
-               }
 
-               [MonoTODO]
-               public override ContentAlignment TextAlign {
-                       get {   return base.TextAlign;  }
-                       set {   base.TextAlign = value; }
+                       set {
+                               if (value && (check_state != CheckState.Checked)) {
+                                       check_state = CheckState.Checked;
+                                       Invalidate();
+                                       UpdateSiblings();
+                                       OnCheckedChanged(EventArgs.Empty);
+                               } else if (!value && (check_state != CheckState.Unchecked)) {
+                                       TabStop = false;
+                                       check_state = CheckState.Unchecked;
+                                       Invalidate();
+                                       OnCheckedChanged(EventArgs.Empty);
+                               }
+                       }
                }
 
-               public void PerformClick()
-               {
-                       Checked = !Checked;
-                       OnClick ( EventArgs.Empty );
+               [DefaultValue(false)]
+               public new bool TabStop {
+                       get { return base.TabStop; }
+                       set { base.TabStop = value; }
                }
 
-               public override string ToString()
-               {
-                       return GetType().FullName.ToString () + ", Checked: " + Checked.ToString ( );
+               [DefaultValue(ContentAlignment.MiddleLeft)]
+               [Localizable(true)]
+               public override ContentAlignment TextAlign {
+                       get { return base.TextAlign; }
+                       set { base.TextAlign = value; }
                }
+               #endregion      // Public Instance Properties
 
-               public event EventHandler AppearanceChanged;
-               public event EventHandler CheckedChanged;
-
-               [MonoTODO]
+               #region Protected Instance Properties
                protected override CreateParams CreateParams {
                        get {
-                               CreateParams createParams = base.CreateParams;
-                               createParams.ClassName = "BUTTON";
-
-                               createParams.Style = (int) (
-                                       (int)WindowStyles.WS_CHILD | 
-                                       (int)WindowStyles.WS_VISIBLE );
-
-                               createParams.Style |= AutoCheckStyle | AppearanceStyle;
-                               createParams.Style |= (int)Win32.ContentAlignment2SystemButtonStyle( TextAlign );
+                               SetStyle(ControlStyles.AllPaintingInWmPaint, true);
+                               SetStyle(ControlStyles.UserPaint, true);
 
-                               return createParams;
+                               return base.CreateParams;
                        }
                }
 
-               protected override ImeMode DefaultImeMode {
-                       get {   return ImeMode.Disable; }
-               }
-
                protected override Size DefaultSize {
-                       get {   return new Size(104,24); }
+                       get {
+                               return ThemeEngine.Current.RadioButtonDefaultSize;
+                       }
                }
+               #endregion      // Protected Instance Properties
 
-               [MonoTODO]
-               protected override AccessibleObject CreateAccessibilityInstance()
-               {
-                       throw new NotImplementedException ();
+               #region Public Instance Methods
+               public void PerformClick() {
+                       OnClick(EventArgs.Empty);
                }
 
-               protected virtual void OnCheckedChanged(EventArgs e)
-               {
-                       if ( CheckedChanged != null )
-                               CheckedChanged ( this, e );
+               public override string ToString() {
+                       return base.ToString() + ", Checked: " + this.Checked;
                }
+               #endregion      // Public Instance Methods
 
-               [MonoTODO]
-               protected override void OnClick(EventArgs e)
-               {
-                       int res = Win32.SendMessage ( Handle, (int)ButtonMessages.BM_GETCHECK, 0, 0);
+               #region Protected Instance Methods
+               protected override AccessibleObject CreateAccessibilityInstance() {
+                       AccessibleObject        ao;
 
-                       bool check = Checked;
+                       ao = base.CreateAccessibilityInstance ();
+                       ao.role = AccessibleRole.RadioButton;
 
-                       if ( res == (int) NativeButtonState.BST_CHECKED ) 
-                               check = true;
-                       else if ( res == (int) NativeButtonState.BST_UNCHECKED ) 
-                               check = false;
+                       return ao;
+               }
 
-                       if ( checked_ != check ) {
-                               checked_ = check;
-                               OnCheckedChanged ( EventArgs.Empty );
-                       }
+               protected virtual void OnCheckedChanged(EventArgs e) {
+                       EventHandler eh = (EventHandler)(Events [CheckedChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
+               }
 
-                       base.OnClick ( e );
+               protected override void OnClick(EventArgs e) {
+                       if (auto_check) {
+                               if (!Checked) {
+                                       Checked = true;
+                               }
+                       } else {
+                               Checked = !Checked;
+                       }
+                       
+                       base.OnClick (e);
                }
 
-               [MonoTODO]
-               protected override void OnEnter(EventArgs e)
-               {
-                       throw new NotImplementedException ();
+               protected override void OnEnter(EventArgs e) {
+                       PerformDefaultCheck ();
+                       base.OnEnter(e);
                }
-               [MonoTODO]
-               protected override void OnHandleCreated(EventArgs e)
-               {
-                       base.OnHandleCreated ( e );
-                       updateCheck ( );
+
+               protected override void OnHandleCreated(EventArgs e) {
+                       base.OnHandleCreated(e);
                }
 
-               [MonoTODO]
-               protected override void OnMouseUp(MouseEventArgs mevent)
-               {
-                       throw new NotImplementedException ();
+               protected override void OnMouseUp(MouseEventArgs mevent) {
+                       base.OnMouseUp(mevent);
                }
-               [MonoTODO]
-               protected override bool ProcessMnemonic(char charCode)
-               {
-                       throw new NotImplementedException ();
+
+               protected override bool ProcessMnemonic(char charCode) {
+                       if (IsMnemonic(charCode, Text) == true) {
+                               Select();
+                               PerformClick();
+                               return true;
+                       }
+                       
+                       return base.ProcessMnemonic(charCode);
                }
+               #endregion      // Protected Instance Methods
 
-               private int AutoCheckStyle
-               {
-                       get { return (int) ( AutoCheck ?  ButtonStyles.BS_AUTORADIOBUTTON : ButtonStyles.BS_RADIOBUTTON ); }
+               #region Events
+               static object AppearanceChangedEvent = new object ();
+               static object CheckedChangedEvent = new object ();
+
+               public event EventHandler AppearanceChanged {
+                       add { Events.AddHandler (AppearanceChangedEvent, value); }
+                       remove { Events.RemoveHandler (AppearanceChangedEvent, value); }
                }
 
-               private int AppearanceStyle
-               {
-                       get { return (int) ( Appearance == Appearance.Normal ? 0 : ButtonStyles.BS_PUSHLIKE ); }
+               public event EventHandler CheckedChanged {
+                       add { Events.AddHandler (CheckedChangedEvent, value); }
+                       remove { Events.RemoveHandler (CheckedChangedEvent, value); }
                }
 
-               private void updateCheck ( ) {
-                       if ( IsHandleCreated ) 
-                               Win32.SendMessage ( Handle, (int) ButtonMessages.BM_SETCHECK, 
-                                                       Checked ? (int) NativeButtonState.BST_CHECKED :
-                                                                 ( int ) NativeButtonState.BST_UNCHECKED, 0 );
+               [Browsable(false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public new event EventHandler DoubleClick {
+                       add { base.DoubleClick += value; }
+                       remove { base.DoubleClick -= value; }
+               }
+               
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public new event MouseEventHandler MouseDoubleClick { 
+                       add { base.MouseDoubleClick += value; }
+                       remove { base.MouseDoubleClick -= value; }
                }
-        }
+               #endregion      // Events
+       }
 }