Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

747 lines
20 KiB
C#

// 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.
//
// Copyright (c) 2004-2006 Novell, Inc.
//
// Authors:
// Peter Bartok pbartok@novell.com
//
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Text;
using System.Runtime.InteropServices;
namespace System.Windows.Forms {
[ClassInterface (ClassInterfaceType.AutoDispatch)]
[ComVisible (true)]
[Designer ("System.Windows.Forms.Design.ButtonBaseDesigner, " + Consts.AssemblySystem_Design,
"System.ComponentModel.Design.IDesigner")]
public abstract class ButtonBase : Control
{
#region Local Variables
private FlatStyle flat_style;
private int image_index;
internal Image image;
internal ImageList image_list;
private ContentAlignment image_alignment;
internal ContentAlignment text_alignment;
private bool is_default;
internal bool is_pressed;
// private bool enter_state;
internal StringFormat text_format;
internal bool paint_as_acceptbutton;
// Properties are 2.0, but variables used in 1.1 for common drawing code
private bool auto_ellipsis;
private FlatButtonAppearance flat_button_appearance;
private string image_key;
private TextImageRelation text_image_relation;
private TextFormatFlags text_format_flags;
private bool use_mnemonic;
private bool use_visual_style_back_color;
#endregion // Local Variables
#region Public Constructors
protected ButtonBase() : base()
{
flat_style = FlatStyle.Standard;
flat_button_appearance = new FlatButtonAppearance (this);
this.image_key = string.Empty;
this.text_image_relation = TextImageRelation.Overlay;
this.use_mnemonic = true;
use_visual_style_back_color = true;
image_index = -1;
image = null;
image_list = null;
image_alignment = ContentAlignment.MiddleCenter;
ImeMode = ImeMode.Disable;
text_alignment = ContentAlignment.MiddleCenter;
is_default = false;
is_pressed = false;
text_format = new StringFormat();
text_format.Alignment = StringAlignment.Center;
text_format.LineAlignment = StringAlignment.Center;
text_format.HotkeyPrefix = HotkeyPrefix.Show;
text_format.FormatFlags |= StringFormatFlags.LineLimit;
text_format_flags = TextFormatFlags.HorizontalCenter;
text_format_flags |= TextFormatFlags.VerticalCenter;
text_format_flags |= TextFormatFlags.TextBoxControl;
SetStyle (ControlStyles.ResizeRedraw |
ControlStyles.Opaque |
ControlStyles.UserMouse |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.CacheText |
ControlStyles.OptimizedDoubleBuffer, true);
SetStyle (ControlStyles.StandardClick, false);
}
#endregion // Public Constructors
#region Public Properties
[Browsable (true)]
[DefaultValue (false)]
[EditorBrowsable (EditorBrowsableState.Always)]
[MWFCategory("Behavior")]
public bool AutoEllipsis {
get { return this.auto_ellipsis; }
set
{
if (this.auto_ellipsis != value) {
this.auto_ellipsis = value;
if (this.auto_ellipsis) {
text_format_flags |= TextFormatFlags.EndEllipsis;
text_format_flags &= ~TextFormatFlags.WordBreak;
} else {
text_format_flags &= ~TextFormatFlags.EndEllipsis;
text_format_flags |= TextFormatFlags.WordBreak;
}
if (Parent != null)
Parent.PerformLayout (this, "AutoEllipsis");
this.Invalidate ();
}
}
}
[Browsable (true)]
[EditorBrowsable (EditorBrowsableState.Always)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)]
[MWFCategory("Layout")]
public override bool AutoSize {
get { return base.AutoSize; }
set { base.AutoSize = value; }
}
public override Color BackColor {
get { return base.BackColor; }
set { base.BackColor = value; }
}
[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
[Browsable (true)]
[MWFCategory("Appearance")]
public FlatButtonAppearance FlatAppearance {
get { return flat_button_appearance; }
}
[Localizable(true)]
[DefaultValue(FlatStyle.Standard)]
[MWFDescription("Determines look of button"), MWFCategory("Appearance")]
public FlatStyle FlatStyle {
get { return flat_style; }
set {
if (flat_style != value) {
flat_style = value;
if (Parent != null)
Parent.PerformLayout (this, "FlatStyle");
Invalidate();
}
}
}
[Localizable(true)]
[MWFDescription("Sets image to be displayed on button face"), MWFCategory("Appearance")]
public Image Image {
get {
if (this.image != null)
return this.image;
if (this.image_index >= 0)
if (this.image_list != null)
return this.image_list.Images[this.image_index];
if (!string.IsNullOrEmpty (this.image_key))
if (this.image_list != null)
return this.image_list.Images[this.image_key];
return null;
}
set {
if (this.image != value) {
this.image = value;
this.image_index = -1;
this.image_key = string.Empty;
this.image_list = null;
if (this.AutoSize && this.Parent != null)
this.Parent.PerformLayout (this, "Image");
Invalidate ();
}
}
}
internal bool ShouldSerializeImage ()
{
return this.Image != null;
}
[Localizable(true)]
[DefaultValue(ContentAlignment.MiddleCenter)]
[MWFDescription("Sets the alignment of the image to be displayed on button face"), MWFCategory("Appearance")]
public ContentAlignment ImageAlign {
get { return image_alignment; }
set {
if (image_alignment != value) {
image_alignment = value;
Invalidate ();
}
}
}
[Localizable(true)]
[DefaultValue(-1)]
[Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
[TypeConverter(typeof(ImageIndexConverter))]
[MWFDescription("Index of image to display, if ImageList is used for button face images"), MWFCategory("Appearance")]
[RefreshProperties (RefreshProperties.Repaint)]
public int ImageIndex {
get {
if (image_list == null)
return -1;
return image_index;
}
set {
if (this.image_index != value) {
this.image_index = value;
this.image = null;
this.image_key = string.Empty;
Invalidate ();
}
}
}
[Localizable (true)]
[DefaultValue ("")]
[Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
[RefreshProperties (RefreshProperties.Repaint)]
[TypeConverter (typeof (ImageKeyConverter))]
[MWFCategory("Appearance")]
public string ImageKey {
get { return this.image_key; }
set {
if (this.image_key != value) {
this.image = null;
this.image_index = -1;
this.image_key = value;
this.Invalidate ();
}
}
}
[DefaultValue(null)]
[MWFDescription("ImageList used for ImageIndex"), MWFCategory("Appearance")]
[RefreshProperties (RefreshProperties.Repaint)]
public ImageList ImageList {
get { return image_list; }
set {
if (image_list != value) {
image_list = value;
if (value != null && image != null)
image = null;
Invalidate ();
}
}
}
[Browsable(false)]
[EditorBrowsable (EditorBrowsableState.Never)]
public new ImeMode ImeMode {
get { return base.ImeMode; }
set { base.ImeMode = value; }
}
[SettingsBindable (true)]
[Editor ("System.ComponentModel.Design.MultilineStringEditor, " + Consts.AssemblySystem_Design,
"System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
public override string Text {
get { return base.Text; }
set { base.Text = value; }
}
[Localizable(true)]
[DefaultValue(ContentAlignment.MiddleCenter)]
[MWFDescription("Alignment for button text"), MWFCategory("Appearance")]
public virtual ContentAlignment TextAlign {
get { return text_alignment; }
set {
if (text_alignment != value) {
text_alignment = value;
text_format_flags &= ~TextFormatFlags.Bottom;
text_format_flags &= ~TextFormatFlags.Top;
text_format_flags &= ~TextFormatFlags.Left;
text_format_flags &= ~TextFormatFlags.Right;
text_format_flags &= ~TextFormatFlags.HorizontalCenter;
text_format_flags &= ~TextFormatFlags.VerticalCenter;
switch (text_alignment) {
case ContentAlignment.TopLeft:
text_format.Alignment=StringAlignment.Near;
text_format.LineAlignment=StringAlignment.Near;
break;
case ContentAlignment.TopCenter:
text_format.Alignment=StringAlignment.Center;
text_format.LineAlignment=StringAlignment.Near;
text_format_flags |= TextFormatFlags.HorizontalCenter;
break;
case ContentAlignment.TopRight:
text_format.Alignment=StringAlignment.Far;
text_format.LineAlignment=StringAlignment.Near;
text_format_flags |= TextFormatFlags.Right;
break;
case ContentAlignment.MiddleLeft:
text_format.Alignment=StringAlignment.Near;
text_format.LineAlignment=StringAlignment.Center;
text_format_flags |= TextFormatFlags.VerticalCenter;
break;
case ContentAlignment.MiddleCenter:
text_format.Alignment=StringAlignment.Center;
text_format.LineAlignment=StringAlignment.Center;
text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;
break;
case ContentAlignment.MiddleRight:
text_format.Alignment=StringAlignment.Far;
text_format.LineAlignment=StringAlignment.Center;
text_format_flags |= TextFormatFlags.VerticalCenter | TextFormatFlags.Right;
break;
case ContentAlignment.BottomLeft:
text_format.Alignment=StringAlignment.Near;
text_format.LineAlignment=StringAlignment.Far;
text_format_flags |= TextFormatFlags.Bottom;
break;
case ContentAlignment.BottomCenter:
text_format.Alignment=StringAlignment.Center;
text_format.LineAlignment=StringAlignment.Far;
text_format_flags |= TextFormatFlags.HorizontalCenter | TextFormatFlags.Bottom;
break;
case ContentAlignment.BottomRight:
text_format.Alignment=StringAlignment.Far;
text_format.LineAlignment=StringAlignment.Far;
text_format_flags |= TextFormatFlags.Bottom | TextFormatFlags.Right;
break;
}
Invalidate();
}
}
}
[Localizable (true)]
[DefaultValue (TextImageRelation.Overlay)]
[MWFCategory("Appearance")]
public TextImageRelation TextImageRelation {
get { return this.text_image_relation; }
set {
if (!Enum.IsDefined (typeof (TextImageRelation), value))
throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for TextImageRelation", value));
if (this.text_image_relation != value) {
this.text_image_relation = value;
if (this.AutoSize && this.Parent != null)
this.Parent.PerformLayout (this, "TextImageRelation");
this.Invalidate ();
}
}
}
[DefaultValue (false)]
[MWFCategory("Behavior")]
public bool UseCompatibleTextRendering {
get { return use_compatible_text_rendering; }
set {
if (use_compatible_text_rendering != value) {
use_compatible_text_rendering = value;
if (Parent != null)
Parent.PerformLayout (this, "UseCompatibleTextRendering");
Invalidate ();
}
}
}
[DefaultValue (true)]
[MWFCategory("Appearance")]
public bool UseMnemonic {
get { return this.use_mnemonic; }
set {
if (this.use_mnemonic != value) {
this.use_mnemonic = value;
if (this.use_mnemonic)
text_format_flags &= ~TextFormatFlags.NoPrefix;
else
text_format_flags |= TextFormatFlags.NoPrefix;
this.Invalidate ();
}
}
}
[MWFCategory("Appearance")]
public bool UseVisualStyleBackColor {
get { return use_visual_style_back_color; }
set {
if (use_visual_style_back_color != value) {
use_visual_style_back_color = value;
Invalidate ();
}
}
}
#endregion // Public Instance Properties
#region Protected Properties
protected override CreateParams CreateParams {
get { return base.CreateParams; }
}
protected override ImeMode DefaultImeMode {
get { return ImeMode.Disable; }
}
protected override Size DefaultSize {
get { return ThemeEngine.Current.ButtonBaseDefaultSize; }
}
protected internal bool IsDefault {
get { return is_default; }
set {
if (is_default != value) {
is_default = value;
Invalidate ();
}
}
}
#endregion // Public Instance Properties
#region Public Methods
// The base calls into GetPreferredSizeCore, which we will override in our subclasses
public override Size GetPreferredSize (Size proposedSize)
{
return base.GetPreferredSize (proposedSize);
}
#endregion
#region Protected Methods
protected override AccessibleObject CreateAccessibilityInstance ()
{
return new ButtonBaseAccessibleObject (this);
}
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
}
protected override void OnEnabledChanged (EventArgs e)
{
base.OnEnabledChanged (e);
}
protected override void OnGotFocus (EventArgs e)
{
Invalidate ();
base.OnGotFocus (e);
}
protected override void OnKeyDown (KeyEventArgs kevent)
{
if (kevent.KeyData == Keys.Space) {
is_pressed = true;
Invalidate ();
kevent.Handled = true;
}
base.OnKeyDown (kevent);
}
protected override void OnKeyUp (KeyEventArgs kevent)
{
if (kevent.KeyData == Keys.Space) {
is_pressed = false;
Invalidate ();
OnClick (EventArgs.Empty);
kevent.Handled = true;
}
base.OnKeyUp (kevent);
}
protected override void OnLostFocus (EventArgs e)
{
Invalidate ();
base.OnLostFocus (e);
}
protected override void OnMouseDown (MouseEventArgs mevent)
{
if ((mevent.Button & MouseButtons.Left) != 0) {
is_pressed = true;
Invalidate ();
}
base.OnMouseDown (mevent);
}
protected override void OnMouseEnter (EventArgs eventargs)
{
is_entered = true;
Invalidate ();
base.OnMouseEnter (eventargs);
}
protected override void OnMouseLeave (EventArgs eventargs)
{
is_entered = false;
Invalidate ();
base.OnMouseLeave (eventargs);
}
protected override void OnMouseMove (MouseEventArgs mevent) {
bool inside = false;
bool redraw = false;
if (ClientRectangle.Contains (mevent.Location))
inside = true;
// If the button was pressed and we leave, release the button press and vice versa
if ((mevent.Button & MouseButtons.Left) != 0) {
if (this.Capture && (inside != is_pressed)) {
is_pressed = inside;
redraw = true;
}
}
if (is_entered != inside) {
is_entered = inside;
redraw = true;
}
if (redraw)
Invalidate ();
base.OnMouseMove (mevent);
}
protected override void OnMouseUp (MouseEventArgs mevent)
{
if (this.Capture && ((mevent.Button & MouseButtons.Left) != 0)) {
this.Capture = false;
if (is_pressed) {
is_pressed = false;
Invalidate ();
} else if ((this.flat_style == FlatStyle.Flat) || (this.flat_style == FlatStyle.Popup)) {
Invalidate ();
}
if (ClientRectangle.Contains (mevent.Location))
if (!ValidationFailed) {
OnClick (EventArgs.Empty);
OnMouseClick (mevent);
}
}
base.OnMouseUp (mevent);
}
protected override void OnPaint (PaintEventArgs pevent)
{
Draw (pevent);
base.OnPaint (pevent);
}
protected override void OnParentChanged (EventArgs e)
{
base.OnParentChanged (e);
}
protected override void OnTextChanged (EventArgs e)
{
Invalidate ();
base.OnTextChanged (e);
}
protected override void OnVisibleChanged (EventArgs e)
{
if (!Visible) {
is_pressed = false;
is_entered = false;
}
base.OnVisibleChanged (e);
}
protected void ResetFlagsandPaint ()
{
// Nothing to do; MS internal
// Should we do Invalidate (); ?
}
protected override void WndProc (ref Message m)
{
switch ((Msg)m.Msg) {
case Msg.WM_LBUTTONDBLCLK: {
HaveDoubleClick ();
break;
}
case Msg.WM_MBUTTONDBLCLK: {
HaveDoubleClick ();
break;
}
case Msg.WM_RBUTTONDBLCLK: {
HaveDoubleClick ();
break;
}
}
base.WndProc (ref m);
}
#endregion // Public Instance Properties
#region Public Events
[Browsable (true)]
[EditorBrowsable (EditorBrowsableState.Always)]
public new event EventHandler AutoSizeChanged {
add { base.AutoSizeChanged += value; }
remove { base.AutoSizeChanged -= value; }
}
[Browsable (false)]
[EditorBrowsable (EditorBrowsableState.Never)]
public new event EventHandler ImeModeChanged {
add { base.ImeModeChanged += value; }
remove { base.ImeModeChanged -= value; }
}
#endregion // Events
#region Internal Properties
internal ButtonState ButtonState {
get {
ButtonState ret = ButtonState.Normal;
if (Enabled) {
// Popup style is only followed as long as the mouse isn't "in" the control
if (is_entered) {
if (flat_style == FlatStyle.Flat) {
ret |= ButtonState.Flat;
}
} else {
if (flat_style == FlatStyle.Flat || flat_style == FlatStyle.Popup) {
ret |= ButtonState.Flat;
}
}
if (is_entered && is_pressed) {
ret |= ButtonState.Pushed;
}
} else {
ret |= ButtonState.Inactive;
if ((flat_style == FlatStyle.Flat) || (flat_style == FlatStyle.Popup)) {
ret |= ButtonState.Flat;
}
}
return ret;
}
}
internal bool Pressed {
get { return this.is_pressed; }
}
// The flags to be used for MeasureText and DrawText
internal TextFormatFlags TextFormatFlags {
get { return this.text_format_flags; }
}
#endregion
#region Internal Methods
// Derived classes should override Draw method and we dont want
// to break the control signature, hence this approach.
internal virtual void Draw (PaintEventArgs pevent)
{
ThemeEngine.Current.DrawButtonBase (pevent.Graphics, pevent.ClipRectangle, this);
}
internal virtual void HaveDoubleClick ()
{
// override me
}
internal override void OnPaintBackgroundInternal (PaintEventArgs e)
{
base.OnPaintBackground (e);
}
#endregion // Internal Methods
#region ButtonBaseAccessibleObject sub-class
[ComVisible (true)]
public class ButtonBaseAccessibleObject : ControlAccessibleObject
{
#region ButtonBaseAccessibleObject Local Variables
private new Control owner;
#endregion // ButtonBaseAccessibleObject Local Variables
#region ButtonBaseAccessibleObject Constructors
public ButtonBaseAccessibleObject (Control owner) : base (owner)
{
if (owner == null)
throw new ArgumentNullException ("owner");
this.owner = owner;
default_action = "Press";
role = AccessibleRole.PushButton;
}
#endregion // ButtonBaseAccessibleObject Constructors
#region Public Properties
public override AccessibleStates State {
get { return base.State; }
}
#endregion
#region ButtonBaseAccessibleObject Methods
public override void DoDefaultAction ()
{
((ButtonBase)owner).OnClick (EventArgs.Empty);
}
#endregion // ButtonBaseAccessibleObject Methods
}
#endregion // ButtonBaseAccessibleObject sub-class
}
}