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 {
33 [ClassInterface (ClassInterfaceType.AutoDispatch)]
35 [Designer ("System.Windows.Forms.Design.ButtonBaseDesigner, " + Consts.AssemblySystem_Design,
36 "System.ComponentModel.Design.IDesigner")]
37 public abstract class ButtonBase : Control
39 #region Local Variables
40 private FlatStyle flat_style;
41 private int image_index;
43 internal ImageList image_list;
44 private ContentAlignment image_alignment;
45 internal ContentAlignment text_alignment;
46 private bool is_default;
47 internal bool is_pressed;
48 // private bool enter_state;
49 internal StringFormat text_format;
50 internal bool paint_as_acceptbutton;
52 // Properties are 2.0, but variables used in 1.1 for common drawing code
53 private bool auto_ellipsis;
54 private FlatButtonAppearance flat_button_appearance;
55 private string image_key;
56 private TextImageRelation text_image_relation;
57 private TextFormatFlags text_format_flags;
58 private bool use_mnemonic;
59 private bool use_visual_style_back_color;
60 #endregion // Local Variables
62 #region Public Constructors
63 protected ButtonBase() : base()
65 flat_style = FlatStyle.Standard;
66 flat_button_appearance = new FlatButtonAppearance (this);
67 this.image_key = string.Empty;
68 this.text_image_relation = TextImageRelation.Overlay;
69 this.use_mnemonic = true;
70 use_visual_style_back_color = true;
74 image_alignment = ContentAlignment.MiddleCenter;
75 ImeMode = ImeMode.Disable;
76 text_alignment = ContentAlignment.MiddleCenter;
79 text_format = new StringFormat();
80 text_format.Alignment = StringAlignment.Center;
81 text_format.LineAlignment = StringAlignment.Center;
82 text_format.HotkeyPrefix = HotkeyPrefix.Show;
83 text_format.FormatFlags |= StringFormatFlags.LineLimit;
85 text_format_flags = TextFormatFlags.HorizontalCenter;
86 text_format_flags |= TextFormatFlags.VerticalCenter;
87 text_format_flags |= TextFormatFlags.TextBoxControl;
89 SetStyle (ControlStyles.ResizeRedraw |
90 ControlStyles.Opaque |
91 ControlStyles.UserMouse |
92 ControlStyles.SupportsTransparentBackColor |
93 ControlStyles.CacheText |
94 ControlStyles.OptimizedDoubleBuffer, true);
95 SetStyle (ControlStyles.StandardClick, false);
97 #endregion // Public Constructors
99 #region Public Properties
101 [DefaultValue (false)]
102 [EditorBrowsable (EditorBrowsableState.Always)]
103 [MWFCategory("Behavior")]
104 public bool AutoEllipsis {
105 get { return this.auto_ellipsis; }
108 if (this.auto_ellipsis != value) {
109 this.auto_ellipsis = value;
111 if (this.auto_ellipsis) {
112 text_format_flags |= TextFormatFlags.EndEllipsis;
113 text_format_flags &= ~TextFormatFlags.WordBreak;
115 text_format_flags &= ~TextFormatFlags.EndEllipsis;
116 text_format_flags |= TextFormatFlags.WordBreak;
120 Parent.PerformLayout (this, "AutoEllipsis");
127 [EditorBrowsable (EditorBrowsableState.Always)]
128 [DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
129 [MWFCategory("Layout")]
130 public override bool AutoSize {
131 get { return base.AutoSize; }
132 set { base.AutoSize = value; }
135 public override Color BackColor {
136 get { return base.BackColor; }
137 set { base.BackColor = value; }
140 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
142 [MWFCategory("Appearance")]
143 public FlatButtonAppearance FlatAppearance {
144 get { return flat_button_appearance; }
148 [DefaultValue(FlatStyle.Standard)]
149 [MWFDescription("Determines look of button"), MWFCategory("Appearance")]
150 public FlatStyle FlatStyle {
151 get { return flat_style; }
153 if (flat_style != value) {
157 Parent.PerformLayout (this, "FlatStyle");
164 [MWFDescription("Sets image to be displayed on button face"), MWFCategory("Appearance")]
167 if (this.image != null)
170 if (this.image_index >= 0)
171 if (this.image_list != null)
172 return this.image_list.Images[this.image_index];
174 if (!string.IsNullOrEmpty (this.image_key))
175 if (this.image_list != null)
176 return this.image_list.Images[this.image_key];
180 if (this.image != value) {
182 this.image_index = -1;
183 this.image_key = string.Empty;
184 this.image_list = null;
186 if (this.AutoSize && this.Parent != null)
187 this.Parent.PerformLayout (this, "Image");
194 internal bool ShouldSerializeImage ()
196 return this.Image != null;
200 [DefaultValue(ContentAlignment.MiddleCenter)]
201 [MWFDescription("Sets the alignment of the image to be displayed on button face"), MWFCategory("Appearance")]
202 public ContentAlignment ImageAlign {
203 get { return image_alignment; }
205 if (image_alignment != value) {
206 image_alignment = value;
214 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
215 [TypeConverter(typeof(ImageIndexConverter))]
216 [MWFDescription("Index of image to display, if ImageList is used for button face images"), MWFCategory("Appearance")]
217 [RefreshProperties (RefreshProperties.Repaint)]
218 public int ImageIndex {
220 if (image_list == null)
226 if (this.image_index != value) {
227 this.image_index = value;
229 this.image_key = string.Empty;
237 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
238 [RefreshProperties (RefreshProperties.Repaint)]
239 [TypeConverter (typeof (ImageKeyConverter))]
240 [MWFCategory("Appearance")]
241 public string ImageKey {
242 get { return this.image_key; }
244 if (this.image_key != value) {
246 this.image_index = -1;
247 this.image_key = value;
254 [MWFDescription("ImageList used for ImageIndex"), MWFCategory("Appearance")]
255 [RefreshProperties (RefreshProperties.Repaint)]
256 public ImageList ImageList {
257 get { return image_list; }
259 if (image_list != value) {
262 if (value != null && image != null)
271 [EditorBrowsable (EditorBrowsableState.Never)]
272 public new ImeMode ImeMode {
273 get { return base.ImeMode; }
274 set { base.ImeMode = value; }
277 [SettingsBindable (true)]
278 [Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
279 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
280 public override string Text {
281 get { return base.Text; }
282 set { base.Text = value; }
286 [DefaultValue(ContentAlignment.MiddleCenter)]
287 [MWFDescription("Alignment for button text"), MWFCategory("Appearance")]
288 public virtual ContentAlignment TextAlign {
289 get { return text_alignment; }
291 if (text_alignment != value) {
292 text_alignment = value;
294 text_format_flags &= ~TextFormatFlags.Bottom;
295 text_format_flags &= ~TextFormatFlags.Top;
296 text_format_flags &= ~TextFormatFlags.Left;
297 text_format_flags &= ~TextFormatFlags.Right;
298 text_format_flags &= ~TextFormatFlags.HorizontalCenter;
299 text_format_flags &= ~TextFormatFlags.VerticalCenter;
301 switch (text_alignment) {
302 case ContentAlignment.TopLeft:
303 text_format.Alignment=StringAlignment.Near;
304 text_format.LineAlignment=StringAlignment.Near;
307 case ContentAlignment.TopCenter:
308 text_format.Alignment=StringAlignment.Center;
309 text_format.LineAlignment=StringAlignment.Near;
310 text_format_flags |= TextFormatFlags.HorizontalCenter;
313 case ContentAlignment.TopRight:
314 text_format.Alignment=StringAlignment.Far;
315 text_format.LineAlignment=StringAlignment.Near;
316 text_format_flags |= TextFormatFlags.Right;
319 case ContentAlignment.MiddleLeft:
320 text_format.Alignment=StringAlignment.Near;
321 text_format.LineAlignment=StringAlignment.Center;
322 text_format_flags |= TextFormatFlags.VerticalCenter;
325 case ContentAlignment.MiddleCenter:
326 text_format.Alignment=StringAlignment.Center;
327 text_format.LineAlignment=StringAlignment.Center;
328 text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;
331 case ContentAlignment.MiddleRight:
332 text_format.Alignment=StringAlignment.Far;
333 text_format.LineAlignment=StringAlignment.Center;
334 text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right;
337 case ContentAlignment.BottomLeft:
338 text_format.Alignment=StringAlignment.Near;
339 text_format.LineAlignment=StringAlignment.Far;
340 text_format_flags |= TextFormatFlags.Bottom;
343 case ContentAlignment.BottomCenter:
344 text_format.Alignment=StringAlignment.Center;
345 text_format.LineAlignment=StringAlignment.Far;
346 text_format_flags |= TextFormatFlags.HorizontalCenter | TextFormatFlags.Bottom;
349 case ContentAlignment.BottomRight:
350 text_format.Alignment=StringAlignment.Far;
351 text_format.LineAlignment=StringAlignment.Far;
352 text_format_flags |= TextFormatFlags.Bottom | TextFormatFlags.Right;
362 [DefaultValue (TextImageRelation.Overlay)]
363 [MWFCategory("Appearance")]
364 public TextImageRelation TextImageRelation {
365 get { return this.text_image_relation; }
367 if (!Enum.IsDefined (typeof (TextImageRelation), value))
368 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextImageRelation", value));
370 if (this.text_image_relation != value) {
371 this.text_image_relation = value;
373 if (this.AutoSize && this.Parent != null)
374 this.Parent.PerformLayout (this, "TextImageRelation");
381 [DefaultValue (false)]
382 [MWFCategory("Behavior")]
383 public bool UseCompatibleTextRendering {
384 get { return use_compatible_text_rendering; }
386 if (use_compatible_text_rendering != value) {
387 use_compatible_text_rendering = value;
389 Parent.PerformLayout (this, "UseCompatibleTextRendering");
395 [DefaultValue (true)]
396 [MWFCategory("Appearance")]
397 public bool UseMnemonic {
398 get { return this.use_mnemonic; }
400 if (this.use_mnemonic != value) {
401 this.use_mnemonic = value;
403 if (this.use_mnemonic)
404 text_format_flags &= ~TextFormatFlags.NoPrefix;
406 text_format_flags |= TextFormatFlags.NoPrefix;
413 [MWFCategory("Appearance")]
414 public bool UseVisualStyleBackColor {
415 get { return use_visual_style_back_color; }
417 if (use_visual_style_back_color != value) {
418 use_visual_style_back_color = value;
423 #endregion // Public Instance Properties
425 #region Protected Properties
426 protected override CreateParams CreateParams {
427 get { return base.CreateParams; }
430 protected override ImeMode DefaultImeMode {
431 get { return ImeMode.Disable; }
434 protected override Size DefaultSize {
435 get { return ThemeEngine.Current.ButtonBaseDefaultSize; }
438 protected internal bool IsDefault {
439 get { return is_default; }
441 if (is_default != value) {
447 #endregion // Public Instance Properties
449 #region Public Methods
450 // The base calls into GetPreferredSizeCore, which we will override in our subclasses
451 public override Size GetPreferredSize (Size proposedSize)
453 return base.GetPreferredSize (proposedSize);
457 #region Protected Methods
458 protected override AccessibleObject CreateAccessibilityInstance ()
460 return new ButtonBaseAccessibleObject (this);
463 protected override void Dispose (bool disposing)
465 base.Dispose (disposing);
468 protected override void OnEnabledChanged (EventArgs e)
470 base.OnEnabledChanged (e);
473 protected override void OnGotFocus (EventArgs e)
479 protected override void OnKeyDown (KeyEventArgs kevent)
481 if (kevent.KeyData == Keys.Space) {
484 kevent.Handled = true;
487 base.OnKeyDown (kevent);
490 protected override void OnKeyUp (KeyEventArgs kevent)
492 if (kevent.KeyData == Keys.Space) {
495 OnClick (EventArgs.Empty);
496 kevent.Handled = true;
499 base.OnKeyUp (kevent);
502 protected override void OnLostFocus (EventArgs e)
505 base.OnLostFocus (e);
508 protected override void OnMouseDown (MouseEventArgs mevent)
510 if ((mevent.Button & MouseButtons.Left) != 0) {
515 base.OnMouseDown (mevent);
518 protected override void OnMouseEnter (EventArgs eventargs)
522 base.OnMouseEnter (eventargs);
525 protected override void OnMouseLeave (EventArgs eventargs)
529 base.OnMouseLeave (eventargs);
532 protected override void OnMouseMove (MouseEventArgs mevent) {
536 if (ClientRectangle.Contains (mevent.Location))
539 // If the button was pressed and we leave, release the button press and vice versa
540 if ((mevent.Button & MouseButtons.Left) != 0) {
541 if (this.Capture && (inside != is_pressed)) {
547 if (is_entered != inside) {
555 base.OnMouseMove (mevent);
558 protected override void OnMouseUp (MouseEventArgs mevent)
560 if (this.Capture && ((mevent.Button & MouseButtons.Left) != 0)) {
561 this.Capture = false;
566 } else if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
570 if (ClientRectangle.Contains (mevent.Location))
571 if (!ValidationFailed) {
572 OnClick (EventArgs.Empty);
573 OnMouseClick (mevent);
577 base.OnMouseUp (mevent);
580 protected override void OnPaint (PaintEventArgs pevent)
583 base.OnPaint (pevent);
586 protected override void OnParentChanged (EventArgs e)
588 base.OnParentChanged (e);
591 protected override void OnTextChanged (EventArgs e)
594 base.OnTextChanged (e);
597 protected override void OnVisibleChanged (EventArgs e)
604 base.OnVisibleChanged (e);
607 protected void ResetFlagsandPaint ()
609 // Nothing to do; MS internal
610 // Should we do Invalidate (); ?
613 protected override void WndProc (ref Message m)
615 switch ((Msg)m.Msg) {
616 case Msg.WM_LBUTTONDBLCLK: {
621 case Msg.WM_MBUTTONDBLCLK: {
626 case Msg.WM_RBUTTONDBLCLK: {
632 base.WndProc (ref m);
634 #endregion // Public Instance Properties
636 #region Public Events
638 [EditorBrowsable (EditorBrowsableState.Always)]
639 public new event EventHandler AutoSizeChanged {
640 add { base.AutoSizeChanged += value; }
641 remove { base.AutoSizeChanged -= value; }
645 [EditorBrowsable (EditorBrowsableState.Never)]
646 public new event EventHandler ImeModeChanged {
647 add { base.ImeModeChanged += value; }
648 remove { base.ImeModeChanged -= value; }
652 #region Internal Properties
653 internal ButtonState ButtonState {
655 ButtonState ret = ButtonState.Normal;
658 // Popup style is only followed as long as the mouse isn't "in" the control
660 if (flat_style == FlatStyle.Flat) {
661 ret |= ButtonState.Flat;
664 if (flat_style == FlatStyle.Flat || flat_style == FlatStyle.Popup) {
665 ret |= ButtonState.Flat;
669 if (is_entered && is_pressed) {
670 ret |= ButtonState.Pushed;
673 ret |= ButtonState.Inactive;
674 if ((flat_style == FlatStyle.Flat) || (flat_style == FlatStyle.Popup)) {
675 ret |= ButtonState.Flat;
682 internal bool Pressed {
683 get { return this.is_pressed; }
686 // The flags to be used for MeasureText and DrawText
687 internal TextFormatFlags TextFormatFlags {
688 get { return this.text_format_flags; }
692 #region Internal Methods
693 // Derived classes should override Draw method and we dont want
694 // to break the control signature, hence this approach.
695 internal virtual void Draw (PaintEventArgs pevent)
697 ThemeEngine.Current.DrawButtonBase (pevent.Graphics, pevent.ClipRectangle, this);
700 internal virtual void HaveDoubleClick ()
705 internal override void OnPaintBackgroundInternal (PaintEventArgs e)
707 base.OnPaintBackground (e);
709 #endregion // Internal Methods
711 #region ButtonBaseAccessibleObject sub-class
713 public class ButtonBaseAccessibleObject : ControlAccessibleObject
715 #region ButtonBaseAccessibleObject Local Variables
716 private new Control owner;
717 #endregion // ButtonBaseAccessibleObject Local Variables
719 #region ButtonBaseAccessibleObject Constructors
720 public ButtonBaseAccessibleObject (Control owner) : base (owner)
723 throw new ArgumentNullException ("owner");
726 default_action = "Press";
727 role = AccessibleRole.PushButton;
729 #endregion // ButtonBaseAccessibleObject Constructors
731 #region Public Properties
732 public override AccessibleStates State {
733 get { return base.State; }
737 #region ButtonBaseAccessibleObject Methods
738 public override void DoDefaultAction ()
740 ((ButtonBase)owner).OnClick (EventArgs.Empty);
742 #endregion // ButtonBaseAccessibleObject Methods
744 #endregion // ButtonBaseAccessibleObject sub-class