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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2004-2006 Novell, Inc.
23 // Peter Bartok pbartok@novell.com
26 using System.ComponentModel;
27 using System.ComponentModel.Design;
29 using System.Drawing.Text;
30 using System.Runtime.InteropServices;
32 namespace System.Windows.Forms {
34 [ClassInterface (ClassInterfaceType.AutoDispatch)]
36 [Designer ("System.Windows.Forms.Design.ButtonBaseDesigner, " + Consts.AssemblySystem_Design,
37 "System.ComponentModel.Design.IDesigner")]
39 public abstract class ButtonBase : Control
41 #region Local Variables
42 private FlatStyle flat_style;
43 private int image_index;
45 internal ImageList image_list;
46 private ContentAlignment image_alignment;
47 internal ContentAlignment text_alignment;
48 private bool is_default;
49 internal bool is_pressed;
50 // private bool enter_state;
51 internal StringFormat text_format;
52 internal bool paint_as_acceptbutton;
54 // Properties are 2.0, but variables used in 1.1 for common drawing code
55 private bool auto_ellipsis;
56 private FlatButtonAppearance flat_button_appearance;
58 private string image_key;
60 private TextImageRelation text_image_relation;
61 private TextFormatFlags text_format_flags;
62 private bool use_mnemonic;
63 private bool use_visual_style_back_color;
64 #endregion // Local Variables
66 #region Public Constructors
67 protected ButtonBase() : base()
69 flat_style = FlatStyle.Standard;
71 flat_button_appearance = new FlatButtonAppearance (this);
72 this.image_key = string.Empty;
73 this.text_image_relation = TextImageRelation.Overlay;
74 this.use_mnemonic = true;
75 use_visual_style_back_color = true;
80 image_alignment = ContentAlignment.MiddleCenter;
81 ImeMode = ImeMode.Disable;
82 text_alignment = ContentAlignment.MiddleCenter;
85 text_format = new StringFormat();
86 text_format.Alignment = StringAlignment.Center;
87 text_format.LineAlignment = StringAlignment.Center;
88 text_format.HotkeyPrefix = HotkeyPrefix.Show;
90 text_format_flags = TextFormatFlags.HorizontalCenter;
91 text_format_flags |= TextFormatFlags.VerticalCenter;
93 SetStyle (ControlStyles.ResizeRedraw |
94 ControlStyles.Opaque |
95 ControlStyles.UserMouse |
96 ControlStyles.SupportsTransparentBackColor |
97 ControlStyles.CacheText |
99 ControlStyles.OptimizedDoubleBuffer, true);
101 ControlStyles.DoubleBuffer, true);
103 SetStyle (ControlStyles.StandardClick, false);
105 #endregion // Public Constructors
107 #region Public Properties
109 [DefaultValue (false)]
110 [EditorBrowsable (EditorBrowsableState.Always)]
117 get { return this.auto_ellipsis; }
120 if (this.auto_ellipsis != value) {
121 this.auto_ellipsis = value;
123 if (this.auto_ellipsis) {
124 text_format_flags |= TextFormatFlags.EndEllipsis;
125 text_format_flags &= ~TextFormatFlags.WordBreak;
127 text_format_flags &= ~TextFormatFlags.EndEllipsis;
128 text_format_flags |= TextFormatFlags.WordBreak;
138 [EditorBrowsable (EditorBrowsableState.Always)]
139 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
140 public override bool AutoSize {
141 get { return base.AutoSize; }
142 set { base.AutoSize = value; }
145 public override Color BackColor {
146 get { return base.BackColor; }
147 set { base.BackColor = value; }
151 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
158 FlatButtonAppearance FlatAppearance {
159 get { return flat_button_appearance; }
163 [DefaultValue(FlatStyle.Standard)]
164 [MWFDescription("Determines look of button"), MWFCategory("Appearance")]
165 public FlatStyle FlatStyle {
166 get { return flat_style; }
168 if (flat_style != value) {
176 [MWFDescription("Sets image to be displayed on button face"), MWFCategory("Appearance")]
179 if (this.image != null)
182 if (this.image_index >= 0)
183 if (this.image_list != null)
184 return this.image_list.Images[this.image_index];
187 if (!string.IsNullOrEmpty (this.image_key))
188 if (this.image_list != null)
189 return this.image_list.Images[this.image_key];
194 if (this.image != value) {
196 this.image_index = -1;
198 this.image_key = string.Empty;
200 this.image_list = null;
203 if (this.AutoSize && this.Parent != null)
204 this.Parent.PerformLayout (this, "Image");
212 internal bool ShouldSerializeImage ()
214 return this.Image != null;
218 [DefaultValue(ContentAlignment.MiddleCenter)]
219 [MWFDescription("Sets the alignment of the image to be displayed on button face"), MWFCategory("Appearance")]
220 public ContentAlignment ImageAlign {
221 get { return image_alignment; }
223 if (image_alignment != value) {
224 image_alignment = value;
232 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
233 [TypeConverter(typeof(ImageIndexConverter))]
234 [MWFDescription("Index of image to display, if ImageList is used for button face images"), MWFCategory("Appearance")]
236 [RefreshProperties (RefreshProperties.Repaint)]
238 public int ImageIndex {
240 if (image_list == null)
246 if (this.image_index != value) {
247 this.image_index = value;
250 this.image_key = string.Empty;
260 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
261 [RefreshProperties (RefreshProperties.Repaint)]
262 [TypeConverter (typeof (ImageKeyConverter))]
263 public string ImageKey {
264 get { return this.image_key; }
266 if (this.image_key != value) {
268 this.image_index = -1;
269 this.image_key = value;
277 [MWFDescription("ImageList used for ImageIndex"), MWFCategory("Appearance")]
279 [RefreshProperties (RefreshProperties.Repaint)]
281 public ImageList ImageList {
282 get { return image_list; }
284 if (image_list != value) {
287 if (value != null && image != null)
296 [EditorBrowsable (EditorBrowsableState.Never)]
297 public new ImeMode ImeMode {
298 get { return base.ImeMode; }
299 set { base.ImeMode = value; }
303 [SettingsBindable (true)]
304 [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
305 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
306 public override string Text {
307 get { return base.Text; }
308 set { base.Text = value; }
313 [DefaultValue(ContentAlignment.MiddleCenter)]
314 [MWFDescription("Alignment for button text"), MWFCategory("Appearance")]
315 public virtual ContentAlignment TextAlign {
316 get { return text_alignment; }
318 if (text_alignment != value) {
319 text_alignment = value;
321 text_format_flags &= ~TextFormatFlags.Bottom;
322 text_format_flags &= ~TextFormatFlags.Top;
323 text_format_flags &= ~TextFormatFlags.Left;
324 text_format_flags &= ~TextFormatFlags.Right;
325 text_format_flags &= ~TextFormatFlags.HorizontalCenter;
326 text_format_flags &= ~TextFormatFlags.VerticalCenter;
328 switch (text_alignment) {
329 case ContentAlignment.TopLeft:
330 text_format.Alignment=StringAlignment.Near;
331 text_format.LineAlignment=StringAlignment.Near;
334 case ContentAlignment.TopCenter:
335 text_format.Alignment=StringAlignment.Center;
336 text_format.LineAlignment=StringAlignment.Near;
337 text_format_flags |= TextFormatFlags.HorizontalCenter;
340 case ContentAlignment.TopRight:
341 text_format.Alignment=StringAlignment.Far;
342 text_format.LineAlignment=StringAlignment.Near;
343 text_format_flags |= TextFormatFlags.Right;
346 case ContentAlignment.MiddleLeft:
347 text_format.Alignment=StringAlignment.Near;
348 text_format.LineAlignment=StringAlignment.Center;
349 text_format_flags |= TextFormatFlags.VerticalCenter;
352 case ContentAlignment.MiddleCenter:
353 text_format.Alignment=StringAlignment.Center;
354 text_format.LineAlignment=StringAlignment.Center;
355 text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;
358 case ContentAlignment.MiddleRight:
359 text_format.Alignment=StringAlignment.Far;
360 text_format.LineAlignment=StringAlignment.Center;
361 text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right;
364 case ContentAlignment.BottomLeft:
365 text_format.Alignment=StringAlignment.Near;
366 text_format.LineAlignment=StringAlignment.Far;
367 text_format_flags |= TextFormatFlags.Bottom;
370 case ContentAlignment.BottomCenter:
371 text_format.Alignment=StringAlignment.Center;
372 text_format.LineAlignment=StringAlignment.Far;
373 text_format_flags |= TextFormatFlags.HorizontalCenter | TextFormatFlags.Bottom;
376 case ContentAlignment.BottomRight:
377 text_format.Alignment=StringAlignment.Far;
378 text_format.LineAlignment=StringAlignment.Far;
379 text_format_flags |= TextFormatFlags.Bottom | TextFormatFlags.Right;
390 [DefaultValue (TextImageRelation.Overlay)]
395 TextImageRelation TextImageRelation {
396 get { return this.text_image_relation; }
398 if (!Enum.IsDefined (typeof (TextImageRelation), value))
399 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextImageRelation", value));
401 if (this.text_image_relation != value) {
402 this.text_image_relation = value;
405 if (this.AutoSize && this.Parent != null)
406 this.Parent.PerformLayout (this, "TextImageRelation");
414 [DefaultValue (false)]
420 bool UseCompatibleTextRendering {
421 get { return use_compatible_text_rendering; }
423 if (use_compatible_text_rendering != value) {
424 use_compatible_text_rendering = value;
430 [DefaultValue (true)]
437 get { return this.use_mnemonic; }
439 if (this.use_mnemonic != value) {
440 this.use_mnemonic = value;
442 if (this.use_mnemonic)
443 text_format_flags &= ~TextFormatFlags.NoPrefix;
445 text_format_flags |= TextFormatFlags.NoPrefix;
457 bool UseVisualStyleBackColor {
458 get { return use_visual_style_back_color; }
460 if (use_visual_style_back_color != value) {
461 use_visual_style_back_color = value;
466 #endregion // Public Instance Properties
468 #region Protected Properties
469 protected override CreateParams CreateParams {
470 get { return base.CreateParams; }
473 protected override ImeMode DefaultImeMode {
474 get { return ImeMode.Disable; }
477 protected override Size DefaultSize {
478 get { return ThemeEngine.Current.ButtonBaseDefaultSize; }
481 protected bool IsDefault {
482 get { return is_default; }
484 if (is_default != value) {
490 #endregion // Public Instance Properties
492 #region Public Methods
494 // The base calls into GetPreferredSizeCore, which we will override in our subclasses
495 public override Size GetPreferredSize (Size proposedSize)
497 return base.GetPreferredSize (proposedSize);
502 #region Protected Methods
503 protected override AccessibleObject CreateAccessibilityInstance ()
505 return new ButtonBaseAccessibleObject (this);
508 protected override void Dispose (bool disposing)
510 base.Dispose (disposing);
513 protected override void OnEnabledChanged (EventArgs e)
515 base.OnEnabledChanged (e);
518 protected override void OnGotFocus (EventArgs e)
524 protected override void OnKeyDown (KeyEventArgs kevent)
526 if (kevent.KeyData == Keys.Space) {
529 kevent.Handled = true;
532 base.OnKeyDown (kevent);
535 protected override void OnKeyUp (KeyEventArgs kevent)
537 if (kevent.KeyData == Keys.Space) {
540 OnClick (EventArgs.Empty);
541 kevent.Handled = true;
544 base.OnKeyUp (kevent);
547 protected override void OnLostFocus (EventArgs e)
550 base.OnLostFocus (e);
553 protected override void OnMouseDown (MouseEventArgs mevent)
555 if ((mevent.Button & MouseButtons.Left) != 0) {
560 base.OnMouseDown (mevent);
563 protected override void OnMouseEnter (EventArgs e)
567 base.OnMouseEnter (e);
570 protected override void OnMouseLeave (EventArgs e)
574 base.OnMouseLeave (e);
577 protected override void OnMouseMove (MouseEventArgs mevent) {
581 if (ClientRectangle.Contains (mevent.Location))
584 // If the button was pressed and we leave, release the button press and vice versa
585 if ((mevent.Button & MouseButtons.Left) != 0) {
586 if (this.Capture && (inside != is_pressed)) {
592 if (is_entered != inside) {
600 base.OnMouseMove (mevent);
603 protected override void OnMouseUp (MouseEventArgs mevent)
605 if (this.Capture && ((mevent.Button & MouseButtons.Left) != 0)) {
606 this.Capture = false;
611 } else if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
615 if (ClientRectangle.Contains (mevent.Location))
616 OnClick (EventArgs.Empty);
619 base.OnMouseUp (mevent);
622 protected override void OnPaint (PaintEventArgs pevent)
625 base.OnPaint (pevent);
628 protected override void OnParentChanged (EventArgs e)
630 base.OnParentChanged (e);
633 protected override void OnTextChanged (EventArgs e)
636 base.OnTextChanged (e);
639 protected override void OnVisibleChanged (EventArgs e)
646 base.OnVisibleChanged (e);
649 protected void ResetFlagsandPaint ()
651 // Nothing to do; MS internal
652 // Should we do Invalidate (); ?
655 protected override void WndProc (ref Message m)
657 switch ((Msg)m.Msg) {
658 case Msg.WM_LBUTTONDBLCLK: {
663 case Msg.WM_MBUTTONDBLCLK: {
668 case Msg.WM_RBUTTONDBLCLK: {
674 base.WndProc (ref m);
676 #endregion // Public Instance Properties
678 #region Public Events
681 [EditorBrowsable (EditorBrowsableState.Always)]
682 public new event EventHandler AutoSizeChanged {
683 add { base.AutoSizeChanged += value; }
684 remove { base.AutoSizeChanged -= value; }
689 [EditorBrowsable (EditorBrowsableState.Never)]
690 public new event EventHandler ImeModeChanged {
691 add { base.ImeModeChanged += value; }
692 remove { base.ImeModeChanged -= value; }
696 #region Internal Properties
697 internal ButtonState ButtonState {
699 ButtonState ret = ButtonState.Normal;
702 // Popup style is only followed as long as the mouse isn't "in" the control
704 if (flat_style == FlatStyle.Flat) {
705 ret |= ButtonState.Flat;
708 if (flat_style == FlatStyle.Flat || flat_style == FlatStyle.Popup) {
709 ret |= ButtonState.Flat;
713 if (is_entered && is_pressed) {
714 ret |= ButtonState.Pushed;
717 ret |= ButtonState.Inactive;
718 if ((flat_style == FlatStyle.Flat) || (flat_style == FlatStyle.Popup)) {
719 ret |= ButtonState.Flat;
726 internal bool Pressed {
727 get { return this.is_pressed; }
730 // The flags to be used for MeasureText and DrawText
731 internal TextFormatFlags TextFormatFlags {
732 get { return this.text_format_flags; }
736 #region Internal Methods
737 // Derived classes should override Draw method and we dont want
738 // to break the control signature, hence this approach.
739 internal virtual void Draw (PaintEventArgs pevent)
741 ThemeEngine.Current.DrawButtonBase (pevent.Graphics, pevent.ClipRectangle, this);
744 internal virtual void HaveDoubleClick ()
749 internal override void OnPaintBackgroundInternal (PaintEventArgs e)
751 base.OnPaintBackground (e);
753 #endregion // Internal Methods
755 #region ButtonBaseAccessibleObject sub-class
757 public class ButtonBaseAccessibleObject : ControlAccessibleObject
759 #region ButtonBaseAccessibleObject Local Variables
760 private new Control owner;
761 #endregion // ButtonBaseAccessibleObject Local Variables
763 #region ButtonBaseAccessibleObject Constructors
764 public ButtonBaseAccessibleObject (Control owner) : base (owner)
767 throw new ArgumentNullException ("owner");
770 default_action = "Press";
771 role = AccessibleRole.PushButton;
773 #endregion // ButtonBaseAccessibleObject Constructors
775 #region Public Properties
777 public override AccessibleStates State {
778 get { return base.State; }
783 #region ButtonBaseAccessibleObject Methods
784 public override void DoDefaultAction ()
786 ((ButtonBase)owner).OnClick (EventArgs.Empty);
788 #endregion // ButtonBaseAccessibleObject Methods
790 #endregion // ButtonBaseAccessibleObject sub-class