|
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms.Design;
namespace ImageControls
{
[Description("Image Button")]
[Designer(typeof(ImageControls.ButtonDesigner))]
public class ImageButton : System.Windows.Forms.Button
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
#region enums
public enum ControlState
{
/// <summary>Button is in the normal state.</summary>
Normal,
/// <summary>Button is in the hover state.</summary>
Pressed,
/// <summary>Button is in the default state.</summary>
Hover,
/// <summary>Button is in the disabled state.</summary>
Disabled
}
#endregion
#region Constructors
public ImageButton()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
}
/// <summary>
/// ImageButton default constructor
/// </summary>
static ImageButton()
{
}
#endregion
#region Instance fields
protected bool autoSize = false;
// These settings approximate the pulse effect
// of buttons on Mac OS X
protected static int PulseInterval = 70;
protected static float PulseGammaMax = 1.8f;
protected static float PulseGammaMin = 0.7f;
protected static float PulseGammaShift = 0.2f;
protected static float PulseGammaReductionThreshold = 0.2f;
protected static float PulseGammaShiftReduction = 0.5f;
// Pulsing
protected Timer timer;
protected float gamma, gammaShift;
// Rectangles to position images on the button face
protected Rectangle rcLeft, rcRight;
// Matrices for transparency transformation
protected ImageAttributes iaDefault;
protected ColorMatrix cmDefault;
// private bool mousePressed;
private bool pulse;
private bool stopPulsingAfterClick;
private int normalIndex;
private int pressedIndex;
private int hoverIndex;
private int disabledIndex;
private ControlState enmState = ControlState.Normal;
private bool bCanClick = false;
#endregion
#region Properties
[Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design", typeof(UITypeEditor))]
[TypeConverter(typeof(ImageIndexConverter))]
[Description( "The index in the ImageList to display for the normal state of the button." )]
[Category( "Appearance" )]
[DefaultValue( "(none)" )]
public int ImageIndexNormal
{
get { return normalIndex; }
set
{
normalIndex = value;
AutoSizeButton();
Invalidate();
}
}
[Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design", typeof(UITypeEditor))]
[TypeConverter(typeof(ImageIndexConverter))]
[Description( "The index in the ImageList for the pressed state of the button." )]
[Category( "Appearance" )]
[DefaultValue( "(none)" )]
public int ImageIndexPressed
{
get { return pressedIndex; }
set
{
pressedIndex = value;
AutoSizeButton();
}
}
[Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design", typeof(UITypeEditor))]
[TypeConverter(typeof(ImageIndexConverter))]
[Description( "The index in the ImageList for the hover state of the button." )]
[Category( "Appearance" )]
[DefaultValue( "(none)" )]
public int ImageIndexHover
{
get { return hoverIndex; }
set
{
hoverIndex = value;
AutoSizeButton();
}
}
[Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design", typeof(UITypeEditor))]
[TypeConverter(typeof(ImageIndexConverter))]
[Description( "The index in the ImageList for the disabled state of the button." )]
[Category( "Appearance" )]
[DefaultValue( "(none)" )]
public int ImageIndexDisabled
{
get { return disabledIndex; }
set
{
disabledIndex = value;
AutoSizeButton();
}
}
[Description( "Determines whether the button pulses." )]
[Category( "Appearance" )]
[DefaultValue( false )]
public bool Pulse
{
get { return pulse; }
set
{
if( Enabled )
{
pulse = value;
if( pulse )
{
StartPulsing();
}
else
{
StopPulsing();
}
}
}
}
[Description( "Determines whether the button stops pulsing after a click event." )]
[Category( "Appearance" )]
[DefaultValue( false )]
public bool StopPulsingAfterClick
{
get
{
return stopPulsingAfterClick;
}
set
{
stopPulsingAfterClick = value;
}
}
[Description( "Determines whether the button automatically resizes itself to fit the 'normal' button graphic." )]
[Category( "Appearance" )]
[DefaultValue( false )]
public bool AutoSize
{
get
{
return autoSize;
}
set
{
autoSize = value;
if( autoSize )
{
AutoSizeButton();
}
}
}
#endregion
#region Methods
protected override void OnCreateControl()
{
base.OnCreateControl ();
InitializeGraphics();
}
// Overridden Event Handlers
protected override void OnClick(EventArgs ea)
{
this.Capture = false;
bCanClick = false;
if (this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition)))
enmState = ControlState.Hover;
else
enmState = ControlState.Normal;
if( stopPulsingAfterClick )
{
pulse = false;
StopPulsing();
}
this.Invalidate();
base.OnClick(ea);
}
protected override void OnMouseEnter(EventArgs ea)
{
base.OnMouseEnter(ea);
enmState = ControlState.Hover;
this.Invalidate();
}
protected override void OnMouseDown(MouseEventArgs mea)
{
base.OnMouseDown(mea);
if (mea.Button == MouseButtons.Left)
{
bCanClick = true;
enmState = ControlState.Pressed;
this.Invalidate();
}
}
protected override void OnMouseMove(MouseEventArgs mea)
{
base.OnMouseMove(mea);
if (ClientRectangle.Contains(mea.X, mea.Y))
{
if (enmState == ControlState.Hover && this.Capture && !bCanClick)
{
bCanClick = true;
enmState = ControlState.Pressed;
this.Invalidate();
}
}
else
{
if (enmState == ControlState.Pressed)
{
bCanClick = false;
enmState = ControlState.Hover;
this.Invalidate();
}
}
}
protected override void OnMouseLeave(EventArgs ea)
{
base.OnMouseLeave(ea);
if( this.Enabled )
enmState = ControlState.Normal;
else
enmState = ControlState.Disabled;
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs pea)
{
this.OnPaintBackground(pea);
if (this.ImageList != null)
{
int index = 0;
switch( enmState )
{
case ControlState.Normal:
index = normalIndex;
break;
case ControlState.Pressed:
index = pressedIndex;
break;
case ControlState.Hover:
index = hoverIndex;
break;
case ControlState.Disabled:
index = disabledIndex;
break;
}
Rectangle destRect = new Rectangle( 0, 0,
pea.ClipRectangle.Width, pea.ClipRectangle.Height);
Rectangle srcRect = new Rectangle( 0, 0,
pea.ClipRectangle.Width, pea.ClipRectangle.Height);
pea.Graphics.DrawImage(ImageList.Images[index],new Rectangle(0,0,pea.ClipRectangle.Width,pea.ClipRectangle.Height), 0, 0, pea.ClipRectangle.Width, pea.ClipRectangle.Height, GraphicsUnit.Pixel, iaDefault); //, destRect, srcRect, units);
}
}
protected void AutoSizeButton()
{
if( autoSize && ImageList != null && ImageList.Images[normalIndex] != null )
{
this.SetClientSizeCore(ImageList.Images[normalIndex].Width, ImageList.Images[normalIndex].Height);
}
}
protected override void OnEnabledChanged(EventArgs ea)
{
base.OnEnabledChanged(ea);
if( this.Enabled )
{
enmState = ControlState.Normal;
}
else
{
enmState = ControlState.Disabled;
pulse = false;
StopPulsing();
timer = null;
}
this.Invalidate();
}
protected virtual void StartPulsing ()
{
if ( Enabled && pulse && !this.DesignModeDetected() )
{
if( timer == null )
{
timer = new Timer( );
timer.Tick += new EventHandler( TimerOnTick );
}
timer.Interval = ImageButton.PulseInterval;
gamma = ImageButton.PulseGammaMax;
gammaShift = -ImageButton.PulseGammaShift;
timer.Start();
}
}
protected virtual void StopPulsing ()
{
if ( timer != null )
{
iaDefault.SetGamma( 1.0f, ColorAdjustType.Bitmap );
timer.Stop();
this.Invalidate();
}
}
public void SetRegion(GraphicsPath gp)
{
this.Region = new Region(gp);
}
protected virtual bool DesignModeDetected()
{
// base.DesignMode always returns false, so try this workaround
IDesignerHost host =
(IDesignerHost) this.GetService( typeof( IDesignerHost ) );
return ( host != null );
}
protected virtual void TimerOnTick( object obj, EventArgs e)
{
// set the new gamma level
if ((gamma - ImageButton.PulseGammaMin < ImageButton.PulseGammaReductionThreshold ) ||
(ImageButton.PulseGammaMax - gamma < ImageButton.PulseGammaReductionThreshold ))
gamma += gammaShift * ImageButton.PulseGammaShiftReduction;
else
gamma += gammaShift;
if ( gamma <= ImageButton.PulseGammaMin || gamma >= ImageButton.PulseGammaMax )
gammaShift = -gammaShift;
iaDefault.SetGamma( gamma, ColorAdjustType.Bitmap );
Invalidate( );
Update( );
}
protected virtual void InitializeGraphics ()
{
// Image attributes used to lighten default buttons
cmDefault = new ColorMatrix();
cmDefault.Matrix33 = 0.75f; // reduce opacity by 25%
iaDefault = new ImageAttributes();
iaDefault.SetColorMatrix( cmDefault, ColorMatrixFlag.Default,
ColorAdjustType.Bitmap );
}
#endregion
#region Component Designer generated code
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if( components != null )
components.Dispose();
}
base.Dispose( disposing );
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I'm a software engineer and consultant working in San Diego, California. I began using .NET during the early alpha releases since I worked for a Microsoft subsidiary then, and now I've focused my career on .NET technologies.
There are a lot of .NET sites out there now, but The Code Project is still top of the heap.