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;
70 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;
89 text_format.FormatFlags |= StringFormatFlags.LineLimit;
91 text_format_flags = TextFormatFlags.HorizontalCenter;
92 text_format_flags |= TextFormatFlags.VerticalCenter;
93 text_format_flags |= TextFormatFlags.TextBoxControl;
95 SetStyle (ControlStyles.ResizeRedraw |
96 ControlStyles.Opaque |
97 ControlStyles.UserMouse |
98 ControlStyles.SupportsTransparentBackColor |
99 ControlStyles.CacheText |
101 ControlStyles.OptimizedDoubleBuffer, true);
103 ControlStyles.DoubleBuffer, true);
105 SetStyle (ControlStyles.StandardClick, false);
107 #endregion // Public Constructors
109 #region Public Properties
111 [DefaultValue (false)]
112 [EditorBrowsable (EditorBrowsableState.Always)]
113 [MWFCategory("Behavior")]
120 get { return this.auto_ellipsis; }
123 if (this.auto_ellipsis != value) {
124 this.auto_ellipsis = value;
126 if (this.auto_ellipsis) {
127 text_format_flags |= TextFormatFlags.EndEllipsis;
128 text_format_flags &= ~TextFormatFlags.WordBreak;
130 text_format_flags &= ~TextFormatFlags.EndEllipsis;
131 text_format_flags |= TextFormatFlags.WordBreak;
135 Parent.PerformLayout (this, "AutoEllipsis");
143 [EditorBrowsable (EditorBrowsableState.Always)]
144 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
145 [MWFCategory("Layout")]
146 public override bool AutoSize {
147 get { return base.AutoSize; }
148 set { base.AutoSize = value; }
151 public override Color BackColor {
152 get { return base.BackColor; }
153 set { base.BackColor = value; }
157 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
159 [MWFCategory("Appearance")]
165 FlatButtonAppearance FlatAppearance {
166 get { return flat_button_appearance; }
170 [DefaultValue(FlatStyle.Standard)]
171 [MWFDescription("Determines look of button"), MWFCategory("Appearance")]
172 public FlatStyle FlatStyle {
173 get { return flat_style; }
175 if (flat_style != value) {
179 Parent.PerformLayout (this, "FlatStyle");
186 [MWFDescription("Sets image to be displayed on button face"), MWFCategory("Appearance")]
189 if (this.image != null)
192 if (this.image_index >= 0)
193 if (this.image_list != null)
194 return this.image_list.Images[this.image_index];
197 if (!string.IsNullOrEmpty (this.image_key))
198 if (this.image_list != null)
199 return this.image_list.Images[this.image_key];
204 if (this.image != value) {
206 this.image_index = -1;
208 this.image_key = string.Empty;
210 this.image_list = null;
213 if (this.AutoSize && this.Parent != null)
214 this.Parent.PerformLayout (this, "Image");
222 internal bool ShouldSerializeImage ()
224 return this.Image != null;
228 [DefaultValue(ContentAlignment.MiddleCenter)]
229 [MWFDescription("Sets the alignment of the image to be displayed on button face"), MWFCategory("Appearance")]
230 public ContentAlignment ImageAlign {
231 get { return image_alignment; }
233 if (image_alignment != value) {
234 image_alignment = value;
242 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
243 [TypeConverter(typeof(ImageIndexConverter))]
244 [MWFDescription("Index of image to display, if ImageList is used for button face images"), MWFCategory("Appearance")]
246 [RefreshProperties (RefreshProperties.Repaint)]
248 public int ImageIndex {
250 if (image_list == null)
256 if (this.image_index != value) {
257 this.image_index = value;
260 this.image_key = string.Empty;
270 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
271 [RefreshProperties (RefreshProperties.Repaint)]
272 [TypeConverter (typeof (ImageKeyConverter))]
273 [MWFCategory("Appearance")]
274 public string ImageKey {
275 get { return this.image_key; }
277 if (this.image_key != value) {
279 this.image_index = -1;
280 this.image_key = value;
288 [MWFDescription("ImageList used for ImageIndex"), MWFCategory("Appearance")]
290 [RefreshProperties (RefreshProperties.Repaint)]
292 public ImageList ImageList {
293 get { return image_list; }
295 if (image_list != value) {
298 if (value != null && image != null)
307 [EditorBrowsable (EditorBrowsableState.Never)]
308 public new ImeMode ImeMode {
309 get { return base.ImeMode; }
310 set { base.ImeMode = value; }
314 [SettingsBindable (true)]
315 [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
316 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
317 public override string Text {
318 get { return base.Text; }
319 set { base.Text = value; }
324 [DefaultValue(ContentAlignment.MiddleCenter)]
325 [MWFDescription("Alignment for button text"), MWFCategory("Appearance")]
326 public virtual ContentAlignment TextAlign {
327 get { return text_alignment; }
329 if (text_alignment != value) {
330 text_alignment = value;
332 text_format_flags &= ~TextFormatFlags.Bottom;
333 text_format_flags &= ~TextFormatFlags.Top;
334 text_format_flags &= ~TextFormatFlags.Left;
335 text_format_flags &= ~TextFormatFlags.Right;
336 text_format_flags &= ~TextFormatFlags.HorizontalCenter;
337 text_format_flags &= ~TextFormatFlags.VerticalCenter;
339 switch (text_alignment) {
340 case ContentAlignment.TopLeft:
341 text_format.Alignment=StringAlignment.Near;
342 text_format.LineAlignment=StringAlignment.Near;
345 case ContentAlignment.TopCenter:
346 text_format.Alignment=StringAlignment.Center;
347 text_format.LineAlignment=StringAlignment.Near;
348 text_format_flags |= TextFormatFlags.HorizontalCenter;
351 case ContentAlignment.TopRight:
352 text_format.Alignment=StringAlignment.Far;
353 text_format.LineAlignment=StringAlignment.Near;
354 text_format_flags |= TextFormatFlags.Right;
357 case ContentAlignment.MiddleLeft:
358 text_format.Alignment=StringAlignment.Near;
359 text_format.LineAlignment=StringAlignment.Center;
360 text_format_flags |= TextFormatFlags.VerticalCenter;
363 case ContentAlignment.MiddleCenter:
364 text_format.Alignment=StringAlignment.Center;
365 text_format.LineAlignment=StringAlignment.Center;
366 text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;
369 case ContentAlignment.MiddleRight:
370 text_format.Alignment=StringAlignment.Far;
371 text_format.LineAlignment=StringAlignment.Center;
372 text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right;
375 case ContentAlignment.BottomLeft:
376 text_format.Alignment=StringAlignment.Near;
377 text_format.LineAlignment=StringAlignment.Far;
378 text_format_flags |= TextFormatFlags.Bottom;
381 case ContentAlignment.BottomCenter:
382 text_format.Alignment=StringAlignment.Center;
383 text_format.LineAlignment=StringAlignment.Far;
384 text_format_flags |= TextFormatFlags.HorizontalCenter | TextFormatFlags.Bottom;
387 case ContentAlignment.BottomRight:
388 text_format.Alignment=StringAlignment.Far;
389 text_format.LineAlignment=StringAlignment.Far;
390 text_format_flags |= TextFormatFlags.Bottom | TextFormatFlags.Right;
401 [DefaultValue (TextImageRelation.Overlay)]
402 [MWFCategory("Appearance")]
407 TextImageRelation TextImageRelation {
408 get { return this.text_image_relation; }
410 if (!Enum.IsDefined (typeof (TextImageRelation), value))
411 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextImageRelation", value));
413 if (this.text_image_relation != value) {
414 this.text_image_relation = value;
417 if (this.AutoSize && this.Parent != null)
418 this.Parent.PerformLayout (this, "TextImageRelation");
426 [DefaultValue (false)]
427 [MWFCategory("Behavior")]
433 bool UseCompatibleTextRendering {
434 get { return use_compatible_text_rendering; }
436 if (use_compatible_text_rendering != value) {
437 use_compatible_text_rendering = value;
439 Parent.PerformLayout (this, "UseCompatibleTextRendering");
445 [DefaultValue (true)]
446 [MWFCategory("Appearance")]
453 get { return this.use_mnemonic; }
455 if (this.use_mnemonic != value) {
456 this.use_mnemonic = value;
458 if (this.use_mnemonic)
459 text_format_flags &= ~TextFormatFlags.NoPrefix;
461 text_format_flags |= TextFormatFlags.NoPrefix;
468 [MWFCategory("Appearance")]
474 bool UseVisualStyleBackColor {
475 get { return use_visual_style_back_color; }
477 if (use_visual_style_back_color != value) {
478 use_visual_style_back_color = value;
483 #endregion // Public Instance Properties
485 #region Protected Properties
486 protected override CreateParams CreateParams {
487 get { return base.CreateParams; }
490 protected override ImeMode DefaultImeMode {
491 get { return ImeMode.Disable; }
494 protected override Size DefaultSize {
495 get { return ThemeEngine.Current.ButtonBaseDefaultSize; }
498 protected internal bool IsDefault {
499 get { return is_default; }
501 if (is_default != value) {
507 #endregion // Public Instance Properties
509 #region Public Methods
511 // The base calls into GetPreferredSizeCore, which we will override in our subclasses
512 public override Size GetPreferredSize (Size proposedSize)
514 return base.GetPreferredSize (proposedSize);
519 #region Protected Methods
520 protected override AccessibleObject CreateAccessibilityInstance ()
522 return new ButtonBaseAccessibleObject (this);
525 protected override void Dispose (bool disposing)
527 base.Dispose (disposing);
530 protected override void OnEnabledChanged (EventArgs e)
532 base.OnEnabledChanged (e);
535 protected override void OnGotFocus (EventArgs e)
541 protected override void OnKeyDown (KeyEventArgs kevent)
543 if (kevent.KeyData == Keys.Space) {
546 kevent.Handled = true;
549 base.OnKeyDown (kevent);
552 protected override void OnKeyUp (KeyEventArgs kevent)
554 if (kevent.KeyData == Keys.Space) {
557 OnClick (EventArgs.Empty);
558 kevent.Handled = true;
561 base.OnKeyUp (kevent);
564 protected override void OnLostFocus (EventArgs e)
567 base.OnLostFocus (e);
570 protected override void OnMouseDown (MouseEventArgs mevent)
572 if ((mevent.Button & MouseButtons.Left) != 0) {
577 base.OnMouseDown (mevent);
580 protected override void OnMouseEnter (EventArgs eventargs)
584 base.OnMouseEnter (eventargs);
587 protected override void OnMouseLeave (EventArgs eventargs)
591 base.OnMouseLeave (eventargs);
594 protected override void OnMouseMove (MouseEventArgs mevent) {
598 if (ClientRectangle.Contains (mevent.Location))
601 // If the button was pressed and we leave, release the button press and vice versa
602 if ((mevent.Button & MouseButtons.Left) != 0) {
603 if (this.Capture && (inside != is_pressed)) {
609 if (is_entered != inside) {
617 base.OnMouseMove (mevent);
620 protected override void OnMouseUp (MouseEventArgs mevent)
622 if (this.Capture && ((mevent.Button & MouseButtons.Left) != 0)) {
623 this.Capture = false;
628 } else if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
632 if (ClientRectangle.Contains (mevent.Location))
633 if (!ValidationFailed) {
634 OnClick (EventArgs.Empty);
636 OnMouseClick (mevent);
641 base.OnMouseUp (mevent);
644 protected override void OnPaint (PaintEventArgs pevent)
647 base.OnPaint (pevent);
650 protected override void OnParentChanged (EventArgs e)
652 base.OnParentChanged (e);
655 protected override void OnTextChanged (EventArgs e)
658 base.OnTextChanged (e);
661 protected override void OnVisibleChanged (EventArgs e)
668 base.OnVisibleChanged (e);
671 protected void ResetFlagsandPaint ()
673 // Nothing to do; MS internal
674 // Should we do Invalidate (); ?
677 protected override void WndProc (ref Message m)
679 switch ((Msg)m.Msg) {
680 case Msg.WM_LBUTTONDBLCLK: {
685 case Msg.WM_MBUTTONDBLCLK: {
690 case Msg.WM_RBUTTONDBLCLK: {
696 base.WndProc (ref m);
698 #endregion // Public Instance Properties
700 #region Public Events
703 [EditorBrowsable (EditorBrowsableState.Always)]
704 public new event EventHandler AutoSizeChanged {
705 add { base.AutoSizeChanged += value; }
706 remove { base.AutoSizeChanged -= value; }
711 [EditorBrowsable (EditorBrowsableState.Never)]
712 public new event EventHandler ImeModeChanged {
713 add { base.ImeModeChanged += value; }
714 remove { base.ImeModeChanged -= value; }
718 #region Internal Properties
719 internal ButtonState ButtonState {
721 ButtonState ret = ButtonState.Normal;
724 // Popup style is only followed as long as the mouse isn't "in" the control
726 if (flat_style == FlatStyle.Flat) {
727 ret |= ButtonState.Flat;
730 if (flat_style == FlatStyle.Flat || flat_style == FlatStyle.Popup) {
731 ret |= ButtonState.Flat;
735 if (is_entered && is_pressed) {
736 ret |= ButtonState.Pushed;
739 ret |= ButtonState.Inactive;
740 if ((flat_style == FlatStyle.Flat) || (flat_style == FlatStyle.Popup)) {
741 ret |= ButtonState.Flat;
748 internal bool Pressed {
749 get { return this.is_pressed; }
752 // The flags to be used for MeasureText and DrawText
753 internal TextFormatFlags TextFormatFlags {
754 get { return this.text_format_flags; }
758 #region Internal Methods
759 // Derived classes should override Draw method and we dont want
760 // to break the control signature, hence this approach.
761 internal virtual void Draw (PaintEventArgs pevent)
763 ThemeEngine.Current.DrawButtonBase (pevent.Graphics, pevent.ClipRectangle, this);
766 internal virtual void HaveDoubleClick ()
771 internal override void OnPaintBackgroundInternal (PaintEventArgs e)
773 base.OnPaintBackground (e);
775 #endregion // Internal Methods
777 #region ButtonBaseAccessibleObject sub-class
779 public class ButtonBaseAccessibleObject : ControlAccessibleObject
781 #region ButtonBaseAccessibleObject Local Variables
782 private new Control owner;
783 #endregion // ButtonBaseAccessibleObject Local Variables
785 #region ButtonBaseAccessibleObject Constructors
786 public ButtonBaseAccessibleObject (Control owner) : base (owner)
789 throw new ArgumentNullException ("owner");
792 default_action = "Press";
793 role = AccessibleRole.PushButton;
795 #endregion // ButtonBaseAccessibleObject Constructors
797 #region Public Properties
799 public override AccessibleStates State {
800 get { return base.State; }
805 #region ButtonBaseAccessibleObject Methods
806 public override void DoDefaultAction ()
808 ((ButtonBase)owner).OnClick (EventArgs.Empty);
810 #endregion // ButtonBaseAccessibleObject Methods
812 #endregion // ButtonBaseAccessibleObject sub-class