Click here to Skip to main content
15,893,622 members
Articles / Programming Languages / XML

Custom Bitmap Button Using C#

Rate me:
Please Sign up or sign in to vote.
4.74/5 (57 votes)
3 Mar 20057 min read 402K   9.7K   154  
An article on creating a bitmap button
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace XCtrls
{
	/// <summary>
	/// possible button states
	/// </summary>
	public enum BtnState
	{
		/// <summary>
		/// The button is disabled.
		/// </summary>		
		Inactive  = 0,
		/// <summary>
		/// The button is in it normal unpressed state
		/// </summary>
		Normal    = 1,
		/// <summary>
		/// The location of the mouse is over the button
		/// </summary>
		MouseOver = 2,
		/// <summary>
		/// The button is currently being pressed
		/// </summary>
		Pushed    = 3,	
	}
	/// <summary>
	/// The purpose of this class is to continue to provide the regular functionality of button class with
	/// some additional bitmap enhancments. These enhancements allow the specification of bitmaps for each 
	/// state of the button. In addition, it makes use of the alignment properties already provided by the 
	/// base button class. Since this class renders the image, it should appear similar accross platforms.	
	/// </summary>
	public class BitmapButton : System.Windows.Forms.Button
	{		
#region Private Variables

		private System.Drawing.Image _ImageNormal                = null;
		private System.Drawing.Image _ImageFocused               = null;
		private System.Drawing.Image _ImagePressed               = null;
		private System.Drawing.Image _ImageMouseOver             = null;
		private System.Drawing.Image _ImageInactive              = null;
		private System.Drawing.Color _BorderColor                = System.Drawing.Color.DarkBlue;
		private System.Drawing.Color _InnerBorderColor           = System.Drawing.Color.LightGray;
		private System.Drawing.Color _InnerBorderColor_Focus     = System.Drawing.Color.LightBlue;
		private System.Drawing.Color _InnerBorderColor_MouseOver = System.Drawing.Color.Gold;
		private System.Drawing.Color _ImageBorderColor           = System.Drawing.Color.Chocolate;
		private bool                 _StretchImage               = false;
		private bool                 _TextDropShadow             = true;
		private int                  _Padding                    = 5;
		private bool                 _OffsetPressedContent       = true;		
		private bool                 _ImageBorderEnabled         = true;
        private bool                 _ImageDropShadow            = true;
		private bool                 _FocusRectangleEnabled      = true;
		private BtnState              btnState                   = BtnState.Normal;
		private bool                  CapturingMouse             = false;

#endregion
#region Public Properties
		[Browsable(false)]
		new public System.Drawing.Image Image
		{
			get{return base.Image;}
			set{base.Image = value;}
		}
		[Browsable(false)]
		new public System.Windows.Forms.ImageList ImageList
		{
			get{return base.ImageList;}
			set{base.ImageList = value;}
		}
		[Browsable(false)]
		new public int ImageIndex
		{
			get{return base.ImageIndex;}
			set{base.ImageIndex = value;}
		}
		/// <summary>
		/// Enable the shadowing of the button text
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("enables the text to cast a shadow"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]			
		public bool TextDropShadow
		{
			get{return _TextDropShadow;}
			set{_TextDropShadow = value;}
		}
		/// <summary>
		/// Enables the dashed focus rectangle
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("enables the focus rectangle"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]			
		public bool FocusRectangleEnabled
		{
			get{return _FocusRectangleEnabled;}
			set{_FocusRectangleEnabled = value;}
		}

		/// <summary>
		/// Enable the shadowing of the image in the button
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("enables the image to cast a shadow"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public bool ImageDropShadow
		{
			get{return _ImageDropShadow;}
			set{_ImageDropShadow = value;}
		}
		/// <summary>
		/// This specifies the color of image border. Note, this is only valid if ImageBorder is enabled.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Color of the border around the image"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Color ImageBorderColor
		{
			get{return _ImageBorderColor;}
			set{_ImageBorderColor = value;}
		}
		/// <summary>
		/// This enables/disables the bordering of the image.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Enables the bordering of the image"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public bool ImageBorderEnabled
		{
			get{return _ImageBorderEnabled;}
			set{_ImageBorderEnabled = value;}
		}
        /// <summary>
        /// Color of the border around the button
        /// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Color of the border around the button"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Color BorderColor
		{
			get{return _BorderColor;}
			set{_BorderColor = value;}
		}
		/// <summary>
		/// Color of the inner border when the button has focus
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Color of the inner border when the button has focus"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Color InnerBorderColor_Focus
		{
			get{return _InnerBorderColor_Focus;}
			set{_InnerBorderColor_Focus = value;}
		}
		/// <summary>
		/// Color of the inner border when the button does not have focus
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Color of the inner border when the button does not hvae focus"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Color InnerBorderColor
		{
			get{return _InnerBorderColor;}
			set{_InnerBorderColor = value;}
		}
		/// <summary>
		/// Color of the inner border when the mouse is over the button.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("color of the inner border when the mouse is over the button"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Color InnerBorderColor_MouseOver
		{
			get{return _InnerBorderColor_MouseOver;}
			set{_InnerBorderColor_MouseOver = value;}
		}
		/// <summary>
		/// Stretches the image across the button
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("stretch the impage to the size of the button"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public bool StretchImage
		{
			get{return _StretchImage;}
			set{_StretchImage = value;}
		}
		/// <summary>
		/// Specifies the padding in units of pixels around the button button elements. Currently,
		/// the button elements consist of the image and text.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("padded pixels around the image and text"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public int Padding
		{
			get{return _Padding;}
			set{_Padding = value;}
		}
		/// <summary>
		/// Set to true if to offset button elements when button is pressed
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Set to true if to offset image/text when button is pressed"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public bool OffsetPressedContent
		{
			get{return 
					_OffsetPressedContent;}
			set{_OffsetPressedContent = value;}
		}
		/// <summary>
		/// Image to be displayed while the button state is in normal state. If the other
		/// states do not specify an image, this image is used as a substitute.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Image to be displayed while the button state is in normal state"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Image ImageNormal
		{
			get{return _ImageNormal;}
			set{_ImageNormal = value;}
		}
		/// <summary>
		/// Specifies an image to use while the button has focus.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Image to be displayed while the button has focus"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Image ImageFocused
		{
			get{return _ImageFocused;}
			set{_ImageFocused = value;}
		}
		/// <summary>
		/// Specifies an image to use while the button is enactive.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Image to be displayed while the button is inactive"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Image ImageInactive
		{
			get{return _ImageInactive;}
			set{_ImageInactive = value;}
		}
		/// <summary>
		/// Specifies an image to use while the button is pressed.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Image to be displayed while the button state is pressed"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Image ImagePressed
		{
				get{return _ImagePressed;}
			set{_ImagePressed = value;}
		}
		/// <summary>
		/// Specifies an image to use while the mouse is over the button.
		/// </summary>
		[Browsable(true),
		CategoryAttribute("Appearance"),
		Description("Image to be displayed while the button state is MouseOver"),
		System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
		]
		public System.Drawing.Image ImageMouseOver
		{
				get{return _ImageMouseOver;}
			set{_ImageMouseOver = value;}
		}
#endregion
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;
		/// <summary>
		/// The BitmapButton constructor
		/// </summary>
		public BitmapButton()
		{
			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();
			// TODO: Add any initialization after the InitComponent call			
			
			//LoadGraphics();
		}
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if( components != null )
					components.Dispose();
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <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


#region Paint Methods
		/// <summary>
		/// This method paints the button in its entirety.
		/// </summary>
		/// <param name="e">paint arguments use to paint the button</param>
		protected override void OnPaint(PaintEventArgs e)
		{				
			CreateRegion(0);			
			paint_Background(e);
			paint_Text(e);
			paint_Image(e);			
			paint_Border(e);
			paint_InnerBorder(e);
			paint_FocusBorder(e);
		}
		/// <summary>
		/// This method fills the background of the button.
		/// </summary>
		/// <param name="e">paint arguments use to paint the button</param>
		private void paint_Background(PaintEventArgs e)
		{
			if(e == null)
				return;
			if(e.Graphics == null)
				return;

			Graphics g =e.Graphics;			
			System.Drawing.Rectangle rect = new Rectangle(0,0,Size.Width,Size.Height);				
            //
			// get color of background
			//			
			System.Drawing.Color color = this.BackColor;;
			if(btnState == BtnState.Inactive)
				color = System.Drawing.Color.LightGray;						
			//
			// intialize ColorArray and Positions Array
			//
			Color[] ColorArray     = null;
			float[] PositionArray  = null;
			//
			// initialize color array for a button that is pushed
			//			
			if(btnState == BtnState.Pushed)
			{
				ColorArray = new Color[]{
									 Blend(this.BackColor,System.Drawing.Color.White,80),
									 Blend(this.BackColor,System.Drawing.Color.White,40),
									 Blend(this.BackColor,System.Drawing.Color.Black,0),
									 Blend(this.BackColor,System.Drawing.Color.Black,0),
									 Blend(this.BackColor,System.Drawing.Color.White,40),
									 Blend(this.BackColor,System.Drawing.Color.White,80),								 
				};
				PositionArray  = new float[]{0.0f,.05f,.40f,.60f,.95f,1.0f};
			}
			//
			// else, initialize color array for a button that is normal or disabled
			//			
			else
			{				
				ColorArray = new Color[]{
										 Blend(color,System.Drawing.Color.White,80),
										 Blend(color,System.Drawing.Color.White,90),
										 Blend(color,System.Drawing.Color.White,30),
										 Blend(color,System.Drawing.Color.White,00),               
										 Blend(color,System.Drawing.Color.Black,30),
										 Blend(color,System.Drawing.Color.Black,20),
				};				
				PositionArray  = new float[]{0.0f,.15f,.40f,.65f,.80f,1.0f};
			}
			//
			// create blend variable for the interpolate the colors
			//
			System.Drawing.Drawing2D.ColorBlend blend = new System.Drawing.Drawing2D.ColorBlend();
			blend.Colors    = ColorArray;
			blend.Positions = PositionArray;
			//
			// create vertical gradient brush
			//
			System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(rect, this.BackColor,Blend(this.BackColor,this.BackColor,10), System.Drawing.Drawing2D.LinearGradientMode.Vertical);
			brush.InterpolationColors = blend;
			//
			// fill the rectangle
			//
			g.FillRectangle(brush, rect);
			//
			// release resources
			//
			brush.Dispose();
		}
		/// <summary>
		/// paints the 1 pixel border around the button. The color of
		/// the border is defined by BorderColor
		/// </summary>
		/// <param name="e">paint arguments use to paint the button</param>
		private void paint_Border(PaintEventArgs e)
		{
			if(e == null)
				return;
			if(e.Graphics == null)
				return;
			//
			// create the pen
			//
            Pen pen = new Pen(this.BorderColor,1);			
			//
			// get the points for the border
			//
			Point[] pts = border_Get(0,0,this.Width-1,this.Height-1);
			//
			// paint the border
			//
			e.Graphics.DrawLines(pen,pts);
			//
			// release resources
			//
			pen.Dispose();
		}
		/// <summary>
		/// paints the focus rectangle. 
		/// </summary>
		/// <param name="e">paint arguments use to paint the button</param>		 
		private void paint_FocusBorder(PaintEventArgs e)
		{
			if(e == null)
				return;
			if(e.Graphics == null)
				return;
            //
			// if the button has focus, and focus rectangle is enabled,
			// draw the focus box
			//
			if (this.Focused) 
			{
				if(FocusRectangleEnabled)
				{
					ControlPaint.DrawFocusRectangle(e.Graphics,	new Rectangle(3, 3, this.Width-6, this.Height-6), System.Drawing.Color.Black, this.BackColor);        
				}
			}
		}
		/// <summary>
		/// paint the inner border of the button.
		/// </summary>
		/// <param name="e">paint arguments use to paint the button</param>		 
		private void paint_InnerBorder(PaintEventArgs e)
		{
			if(e == null)
				return;
			if(e.Graphics == null)
				return;

			Graphics g =e.Graphics;			
			System.Drawing.Rectangle rect = new Rectangle(0,0,Size.Width,Size.Height);				

			System.Drawing.Color color = this.BackColor;
			//
			// get color of inner border
			//
			switch(btnState)
			{
				case BtnState.Inactive:
					color = System.Drawing.Color.Gray;
					break;
				case BtnState.Normal:                    
					if(this.Focused)
						color = this.InnerBorderColor_Focus;
					else
						color = this.InnerBorderColor;
					break;
				case BtnState.Pushed:
					color = Blend(InnerBorderColor_Focus,System.Drawing.Color.Black,10);
					break;
				case BtnState.MouseOver:
					color = InnerBorderColor_MouseOver;
					break;
			}
			//
			// populate color and position arrays
			//			
			Color[] ColorArray    = null;
            float[] PositionArray = null;
			if(btnState == BtnState.Pushed)
			{
				ColorArray = new System.Drawing.Color [] {
									   Blend(color,System.Drawing.Color.Black,20),
                                       Blend(color,System.Drawing.Color.Black,10),
                                       Blend(color,System.Drawing.Color.White,00),               
                                       Blend(color,System.Drawing.Color.White,50),
									   Blend(color,System.Drawing.Color.White,85),
									   Blend(color,System.Drawing.Color.White,90),
				};				
				PositionArray = new float[] {0.0f,.20f,.50f,.60f,.90f,1.0f};
			}
			else
			{
				ColorArray = new System.Drawing.Color [] {
									   Blend(color,System.Drawing.Color.White,80),
									   Blend(color,System.Drawing.Color.White,60),
									   Blend(color,System.Drawing.Color.White,10),
									   Blend(color,System.Drawing.Color.White,00),               
									   Blend(color,System.Drawing.Color.Black,20),
									   Blend(color,System.Drawing.Color.Black,50),
				};				
				PositionArray = new float[] {0.0f,.20f,.50f,.60f,.90f,1.0f};
			}
			//
			// create blend object
			//
			System.Drawing.Drawing2D.ColorBlend blend = new System.Drawing.Drawing2D.ColorBlend();
			blend.Colors    = ColorArray;
			blend.Positions = PositionArray;
            //
			// create gradient brush and pen
			//
			System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(rect, this.BackColor,Blend(this.BackColor,this.BackColor,10), System.Drawing.Drawing2D.LinearGradientMode.Vertical);
			brush.InterpolationColors = blend;
			System.Drawing.Pen pen0 = new System.Drawing.Pen(brush,1);
			//
			// get points array to draw the line
			//
			Point[] pts = border_Get(0,0,this.Width-1,this.Height-1);
			//
			// draw line 0
			//
			this.border_Contract(1,ref pts);
			e.Graphics.DrawLines(pen0,pts);
			//
			// draw line 1
			//			
			this.border_Contract(1,ref pts);
			e.Graphics.DrawLines(pen0,pts);
			//
			// release resources
			//
			pen0.Dispose();			
			brush.Dispose();
		}
		/// <summary>
		/// This method paints the text and text shadow for the button.
		/// </summary>
		/// <param name="e">paint arguments use to paint the button</param>		 
		private void paint_Text(PaintEventArgs e)
		{
			if(e == null)
				return;
			if(e.Graphics == null)
				return;	
			System.Drawing.Rectangle rect = GetTextDestinationRect();
			//
			// do offset if button is pushed
			//
			if( (btnState == BtnState.Pushed) && (OffsetPressedContent) )
			       rect.Offset(1,1);
			//
			// caculate bounding rectagle for the text
			//
			System.Drawing.SizeF size = txt_Size(e.Graphics,this.Text,this.Font);
			//
			// calculate the starting location to paint the text
			//
			System.Drawing.Point pt = Calculate_LeftEdgeTopEdge(this.TextAlign, rect, (int) size.Width, (int) size.Height);
            //
			// If button state is inactive, paint the inactive text
			//
			if(btnState == BtnState.Inactive)
			{
				e.Graphics.DrawString(this.Text,this.Font, new SolidBrush(System.Drawing.Color.White),pt.X+1,pt.Y+1);					
				e.Graphics.DrawString(this.Text,this.Font, new SolidBrush(System.Drawing.Color.FromArgb(50,50,50)),pt.X,pt.Y);	
			}
			//
			// else, paint the text and text shadow
		    //
			else
			{
			    //
				// paint text shadow
				//
				if(TextDropShadow)
				{
					System.Drawing.Brush TransparentBrush0 = new System.Drawing.SolidBrush( System.Drawing.Color.FromArgb(50, System.Drawing.Color.Black  ) ) ;
					System.Drawing.Brush TransparentBrush1 = new System.Drawing.SolidBrush( System.Drawing.Color.FromArgb(20, System.Drawing.Color.Black  ) ) ;

					e.Graphics.DrawString(this.Text,this.Font, TransparentBrush0,pt.X,pt.Y+1);				
					e.Graphics.DrawString(this.Text,this.Font, TransparentBrush0,pt.X+1,pt.Y);				
			
					e.Graphics.DrawString(this.Text,this.Font, TransparentBrush1,pt.X+1,pt.Y+1);	
					e.Graphics.DrawString(this.Text,this.Font, TransparentBrush1,pt.X,pt.Y+2);	
					e.Graphics.DrawString(this.Text,this.Font, TransparentBrush1,pt.X+2,pt.Y);	

                    TransparentBrush0.Dispose();
					TransparentBrush1.Dispose();
				}
				//
				// paint text
				//
				e.Graphics.DrawString(this.Text,this.Font, new SolidBrush(this.ForeColor),pt.X,pt.Y);	
			}  
		}
		/// <summary>
		/// Paints a border around the image. If Image drop shadow is enabled,
		/// a shodow is drawn too.
		/// </summary>
		/// <param name="g">The graphics object</param>
		/// <param name="ImageRect">the rectangle region of the image</param>
		private void paint_ImageBorder(System.Drawing.Graphics g, System.Drawing.Rectangle ImageRect)		
		{
			System.Drawing.Rectangle rect = ImageRect;

			//
			// If ImageDropShadow = true, draw shadow
			//
			if(ImageDropShadow)
			{
				System.Drawing.Pen p0 = new System.Drawing.Pen(System.Drawing.Color.FromArgb(80,0,0,0));
				System.Drawing.Pen p1 = new System.Drawing.Pen(System.Drawing.Color.FromArgb(40,0,0,0));
				g.DrawLine(p0, new Point(rect.Right,rect.Bottom),new Point(rect.Right+1,rect.Bottom));
				g.DrawLine(p0, new Point(rect.Right+1,rect.Top+1),new Point(rect.Right+1,rect.Bottom+0));
				g.DrawLine(p1, new Point(rect.Right+2,rect.Top+2),new Point(rect.Right+2,rect.Bottom+1));
				g.DrawLine(p0, new Point(rect.Left+1,rect.Bottom+1),new Point(rect.Right+0,rect.Bottom+1));
				g.DrawLine(p1, new Point(rect.Left+1,rect.Bottom+2),new Point(rect.Right+1,rect.Bottom+2));
			}
			//
			// Draw Image Border
			//
			if(ImageBorderEnabled)
			{
				Color[] ColorArray    = null;	
				float[] PositionArray = null;				
				System.Drawing.Color color = this.ImageBorderColor;
				if(!this.Enabled)
					color = System.Drawing.Color.LightGray;
				//
				// initialize color and position array
				//
				ColorArray = new Color[]{
											Blend(color,System.Drawing.Color.White,40),
											Blend(color,System.Drawing.Color.White,20),
											Blend(color,System.Drawing.Color.White,30),
											Blend(color,System.Drawing.Color.White,00),               
											Blend(color,System.Drawing.Color.Black,30),
											Blend(color,System.Drawing.Color.Black,70),
				};				
				PositionArray = new float[]{0.0f,.20f,.50f,.60f,.90f,1.0f};
				//
				// create blend object
				//
				System.Drawing.Drawing2D.ColorBlend blend = new System.Drawing.Drawing2D.ColorBlend();
				blend.Colors    = ColorArray;
				blend.Positions = PositionArray;
				//
				// create brush and pens
				//
				System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(rect, this.BackColor,Blend(this.BackColor,this.BackColor,10), System.Drawing.Drawing2D.LinearGradientMode.Vertical);
				brush.InterpolationColors = blend;
				System.Drawing.Pen pen0 = new System.Drawing.Pen(brush,1);
				System.Drawing.Pen pen1 = new System.Drawing.Pen(System.Drawing.Color.Black);
				//
				// calculate points to draw line
				//
				rect.Inflate(1,1);
				Point[] pts = border_Get(rect.Left,rect.Top,rect.Width,rect.Height);
				this.border_Contract(1,ref pts);
				//
				// draw line 0
				//
				g.DrawLines(pen1,pts);
				//
				// draw line 1
				//
				this.border_Contract(1,ref pts);
				g.DrawLines(pen0,pts);
				//
				// release resources
				//
				pen1.Dispose();
				pen0.Dispose();
				brush.Dispose();
			}
		}
		/// <summary>
		/// Paints the image on the button.
		/// </summary>
		/// <param name="e"></param>

		private void paint_Image(PaintEventArgs e)
		{
			
			if(e == null)
				return;
			if(e.Graphics == null)
				return;
			Image image = GetCurrentImage(btnState);			

			if(image != null)
			{
				Graphics g =e.Graphics;
				System.Drawing.Rectangle rect = GetImageDestinationRect();

				if( (btnState == BtnState.Pushed) && (_OffsetPressedContent) )
					rect.Offset(1,1);
				if(this.StretchImage)
				{
					g.DrawImage(image,rect, 0, 0 ,image.Width,image.Height, GraphicsUnit.Pixel);
				}
				else
				{		
					System.Drawing.Rectangle r = GetImageDestinationRect();
					//g.DrawImage(image,rect.Left,rect.Top);
					g.DrawImage(image,rect, 0, 0 ,image.Width,image.Height, GraphicsUnit.Pixel);					
				}
				paint_ImageBorder(g,rect);
			}
		}
#endregion
#region Helper Methods
		/// <summary>
		/// Calculates the required size to draw a text string
		/// </summary>
		/// <param name="g">the graphics object</param>
		/// <param name="strText">string to calculate text region</param>
		/// <param name="font">font to use for the string</param>
		/// <returns>returns the size required to draw a text string</returns>
		private System.Drawing.SizeF txt_Size(Graphics g,string strText,Font font)
		{
			System.Drawing.SizeF size = g.MeasureString(strText,font);
			return (size);		   
		}
		/// <summary>
		/// Calculates the rectangular region used for text display.
		/// </summary>
		/// <returns>returns the rectangular region for the text display</returns>
		private System.Drawing.Rectangle GetTextDestinationRect()
		{
			System.Drawing.Rectangle ImageRect = GetImageDestinationRect();
			System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0,0,0,0);
			switch(this.ImageAlign)
			{					
				case System.Drawing.ContentAlignment.BottomCenter:
					rect = new System.Drawing.Rectangle(0,0,this.Width,ImageRect.Top);
					break;
				case System.Drawing.ContentAlignment.BottomLeft:
					rect = new System.Drawing.Rectangle(0,0,this.Width,ImageRect.Top);
					break;
				case System.Drawing.ContentAlignment.BottomRight:
                    rect = new System.Drawing.Rectangle(0,0,this.Width,ImageRect.Top);
					break;
				case System.Drawing.ContentAlignment.MiddleCenter:
					rect = new System.Drawing.Rectangle(0,ImageRect.Bottom,this.Width,this.Height-ImageRect.Bottom);
					break;
				case System.Drawing.ContentAlignment.MiddleLeft:						
					rect = new System.Drawing.Rectangle(ImageRect.Right,0,this.Width-ImageRect.Right,this.Height);
					break;
				case System.Drawing.ContentAlignment.MiddleRight:
					rect = new System.Drawing.Rectangle(0,0,ImageRect.Left,this.Height);
					break;
				case System.Drawing.ContentAlignment.TopCenter:
					rect = new System.Drawing.Rectangle(0,ImageRect.Bottom,this.Width,this.Height-ImageRect.Bottom);
					break;
				case System.Drawing.ContentAlignment.TopLeft:
					rect = new System.Drawing.Rectangle(0,ImageRect.Bottom,this.Width,this.Height-ImageRect.Bottom);
					break;
				case System.Drawing.ContentAlignment.TopRight:
					rect = new System.Drawing.Rectangle(0,ImageRect.Bottom,this.Width,this.Height-ImageRect.Bottom);
					break;				
			}
			rect.Inflate(-this.Padding,-this.Padding);
			return (rect);
		}
		/// <summary>
		/// Calculates the rectangular region used for image display.
		/// </summary>
		/// <returns>returns the rectangular region used to display the image</returns>
		private System.Drawing.Rectangle GetImageDestinationRect()
		{
			System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0,0,0,0);
			System.Drawing.Image image = GetCurrentImage(this.btnState);
			if(image!=null)
			{
				if(this.StretchImage)
				{
					rect.Width = this.Width;
					rect.Height= this.Height;					
				}
				else
				{
					rect.Width  = image.Width;
					rect.Height = image.Height;					
					System.Drawing.Rectangle drect = new System.Drawing.Rectangle(0,0,this.Width,this.Height);
					drect.Inflate(-this.Padding,-this.Padding);
					System.Drawing.Point pt = Calculate_LeftEdgeTopEdge(this.ImageAlign,drect, image.Width,image.Height);
					rect.Offset(pt);
				}
			}			
			return(rect);
		}
		/// <summary>
		/// This method is used to retrieve the image used by the button for the given state.
		/// </summary>
		/// <param name="btnState">holds the state of the button</param>
		/// <returns>returns the button Image</returns>
		private System.Drawing.Image GetCurrentImage(BtnState btnState)
		{
			System.Drawing.Image image = ImageNormal;
			switch(btnState)
			{
				case BtnState.Normal:
					if(this.Focused)
					{
						if(this.ImageFocused != null)
							image = this.ImageFocused;
					}
					break;
				case BtnState.MouseOver:
					if(ImageMouseOver != null)
						image = ImageMouseOver;
					break;
				case BtnState.Pushed:
					if(ImagePressed != null)
						image = ImagePressed;
					break;
				case BtnState.Inactive:
					if(ImageInactive != null)
						image = ImageInactive;
					else
					{
						if(image != null)
						{
							ImageInactive = ConvertToGrayscale( new Bitmap(ImageNormal));
						}
						image = ImageNormal;
					}
					break;
			}
			return(image);
		}
		/// <summary>
		/// converts a bitmap image to grayscale
		/// </summary>
		/// <param name="source">bitmap source</param>
		/// <returns>returns a grayscaled bitmap</returns>
		public Bitmap ConvertToGrayscale(Bitmap source)
		{
			Bitmap bm = new Bitmap(source.Width,source.Height);
			for(int y=0;y<bm.Height;y++)
			{
				for(int x=0;x<bm.Width;x++)
				{
					Color c=source.GetPixel(x,y);
					int luma = (int)(c.R*0.3 + c.G*0.59+ c.B*0.11);
					bm.SetPixel(x,y,Color.FromArgb(luma,luma,luma));
				}
			}
			return bm;
		}
		/// <summary>
		/// calculates the left/top edge for content.
		/// </summary>
		/// <param name="Alignment">the alignment of the content</param>
		/// <param name="rect">rectagular region to place content</param>
		/// <param name="nWidth">with of content</param>
		/// <param name="nHeight">height of content</param>
		/// <returns>returns the left/top edge to place content</returns>
		private System.Drawing.Point Calculate_LeftEdgeTopEdge(System.Drawing.ContentAlignment Alignment, System.Drawing.Rectangle rect, int nWidth, int nHeight)
		{
			System.Drawing.Point pt = new System.Drawing.Point(0,0);
			switch(Alignment)
			{					
				case System.Drawing.ContentAlignment.BottomCenter:
					pt.X = (rect.Width - nWidth)/2;
					pt.Y = rect.Height - nHeight;					
					break;
				case System.Drawing.ContentAlignment.BottomLeft:
					pt.X = 0;
					pt.Y = rect.Height - nHeight;
					break;
				case System.Drawing.ContentAlignment.BottomRight:
					pt.X = rect.Width - nWidth;
					pt.Y = rect.Height - nHeight;
					break;
				case System.Drawing.ContentAlignment.MiddleCenter:
					pt.X = (rect.Width - nWidth)/2;
					pt.Y = (rect.Height - nHeight)/2;
					break;
				case System.Drawing.ContentAlignment.MiddleLeft:						
					pt.X = 0;
					pt.Y = (rect.Height - nHeight)/2;						
					break;
				case System.Drawing.ContentAlignment.MiddleRight:
					pt.X = rect.Width - nWidth;
					pt.Y = (rect.Height - nHeight)/2;						
					break;
				case System.Drawing.ContentAlignment.TopCenter:
					pt.X = (rect.Width - nWidth)/2;
					pt.Y = 0;
					break;
				case System.Drawing.ContentAlignment.TopLeft:
					pt.X = 0;
					pt.Y = 0;
					break;
				case System.Drawing.ContentAlignment.TopRight:
					pt.X = rect.Width - nWidth;
					pt.Y = 0;
					break;
			}
			pt.X += rect.Left;
			pt.Y += rect.Top;
			return(pt);
		}
		/// <summary>
		/// creates the region for the control. The region will have curved edges. 
		/// This prevents any drawing outside of the region.
		/// </summary>
		private void CreateRegion(int nContract)
		{
			Point[] points = border_Get(0,0,this.Width,this.Height);
			border_Contract(nContract,ref points);
	        System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
	        path.AddLines(points);
	        this.Region = new Region(path);	        
		}		
		/// <summary>
		/// contract the array of points that define the border.
		/// </summary>
		/// <param name="nPixel">number of pixels to conract</param>
		/// <param name="pts">array of points that define the border</param>
		private void border_Contract(int nPixel, ref Point[] pts)
		{
			int a = nPixel;
			pts[0].X  += a;  pts[0].Y += a;
			pts[1].X  -= a;  pts[1].Y += a;
			pts[2].X  -= a;  pts[2].Y += a;
			pts[3].X  -= a;  pts[3].Y += a;
			pts[4].X  -= a;  pts[4].Y -= a;
			pts[5].X  -= a;  pts[5].Y -= a;
			pts[6].X  -= a;  pts[6].Y -= a;
			pts[7].X  += a;  pts[7].Y -= a;
			pts[8].X  += a;  pts[8].Y -= a;
			pts[9].X  += a;  pts[9].Y -= a;
			pts[10].X += a;  pts[10].Y += a;
			pts[11].X += a;  pts[10].Y += a;			
		}
		/// <summary>
		/// calculates the array of points that make up a border
		/// </summary>
		/// <param name="nLeftEdge">left edge of border</param>
		/// <param name="nTopEdge">top edge of border</param>
		/// <param name="nWidth">width of border</param>
		/// <param name="nHeight">height of border</param>
		/// <returns>returns an array of points that make up the border</returns>
		private Point[] border_Get(int nLeftEdge, int nTopEdge, int nWidth, int nHeight)
		{			
			int X = nWidth;
			int Y = nHeight;
			Point[] points = 
			{
				new Point(1   , 0  ),
				new Point(X-1 , 0  ),
				new Point(X-1 , 1  ),
				new Point(X   , 1  ),
				new Point(X   , Y-1),
				new Point(X-1 , Y-1),
				new Point(X-1 , Y  ),
				new Point(1   , Y  ),
				new Point(1   , Y-1),
				new Point(0   , Y-1),
				new Point(0   , 1  ),
				new Point(1   , 1  )
			};		
			for(int i = 0; i < points.Length; i++)			
			{					
				points[i].Offset(nLeftEdge,nTopEdge);
			}
			return points;
		}
		/// <summary>
		/// Increments or decrements the red/green/blue values of a color. It enforces that the
		/// values do not go out of the bounds of 0..255
		/// </summary>
		/// <param name="SColor">source color</param>
		/// <param name="RED">red shift</param>
		/// <param name="GREEN">green shift</param>
		/// <param name="BLUE">blue shift</param>
		/// <returns>returns the calculated color</returns>
		private static Color Shade(Color SColor,int RED, int GREEN, int BLUE)
		{   
			int r = SColor.R;
			int g = SColor.G;
			int b = SColor.B;
								   
			r += RED;
			if (r > 0xFF) r = 0xFF;
			if (r < 0)    r = 0; 
   
			g += GREEN; 
			if (g > 0xFF) g = 0xFF;
			if (g < 0)    g = 0; 
   
			b += BLUE; 
			if (b > 0xFF) b = 0xFF;
			if (b < 0)    b = 0; 

			return Color.FromArgb(r,g,b);   
		}
		/// <summary>
		/// Calculates a blended color using the specified parameters. 
		/// </summary>
		/// <param name="SColor">Source Color (color moving from)</param>
		/// <param name="DColor">Dest Color (color movving towards)</param>
		/// <param name="Percentage">Percentage of Dest Color (0..100)</param>
		/// <returns></returns>
		private static Color Blend(Color SColor, Color DColor, int Percentage)
		{	
			int r = SColor.R + ((DColor.R - SColor.R)*Percentage)/100;
			int g = SColor.G + ((DColor.G - SColor.G)*Percentage)/100;
			int b = SColor.B + ((DColor.B - SColor.B)*Percentage)/100;
			return Color.FromArgb(r,g,b);
		}
#endregion
#region Events Methods
		/// <summary>
		/// Mouse Down Event:
		/// set BtnState to Pushed and Capturing mouse to true
		/// </summary>
		/// <param name="e"></param>
		protected override void OnMouseDown(MouseEventArgs e)
		{
			base.OnMouseDown (e);
			this.Capture = true;
			this.CapturingMouse = true;
			btnState = BtnState.Pushed;			
			this.Invalidate();
		}
		/// <summary>
		/// Mouse Up Event:
		/// Set BtnState to Normal and set CapturingMouse to false
		/// </summary>
		/// <param name="e"></param>
		protected override void OnMouseUp(MouseEventArgs e)
		{
			base.OnMouseUp (e);
			btnState = BtnState.Normal;			
			this.Invalidate();
			this.CapturingMouse = false;
			this.Capture = false;			
			this.Invalidate();
		}
		/// <summary>
		/// Mouse Leave Event:
		/// Set BtnState to normal if we CapturingMouse = true
		/// </summary>
		/// <param name="e"></param>
		protected override void OnMouseLeave(EventArgs e)
		{
			base.OnMouseLeave (e);
			if(!CapturingMouse)
			{
				btnState = BtnState.Normal;
				this.Invalidate();
			}			   
		}
		/// <summary>
		/// Mouse Move Event:
		/// If CapturingMouse = true and mouse coordinates are within button region, 
		/// set BtnState to Pushed, otherwise set BtnState to Normal.
		/// If CapturingMouse = false, then set BtnState to MouseOver
		/// </summary>
		/// <param name="e"></param>
		protected override void OnMouseMove(MouseEventArgs e)
		{			
			base.OnMouseMove (e);
			if(CapturingMouse)
			{
				System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0,0,this.Width,this.Height);						
				btnState = BtnState.Normal;
				if( (e.X >= rect.Left) && (e.X <= rect.Right) )
				{
					if( (e.Y >= rect.Top) && (e.Y <= rect.Bottom) )
					{
						btnState = BtnState.Pushed;
					}
				}		
				this.Capture = true;	
				this.Invalidate();
			}
			else
			{	
				//if(!this.Focused)
				{
					if(btnState != BtnState.MouseOver)
					{
						btnState = BtnState.MouseOver;
						this.Invalidate();
					}
				}
			}
		}
		/// <summary>
		/// Enable/Disable Event:
		/// If button became enabled, set BtnState to Normal
		/// else set BtnState to Inactive
		/// </summary>
		/// <param name="e"></param>
		protected override void OnEnabledChanged(EventArgs e)
		{			
			base.OnEnabledChanged (e);
			if(this.Enabled)
			{
				this.btnState = BtnState.Normal;
			}
			else
			{
				this.btnState = BtnState.Inactive;				
			}
			this.Invalidate();
		}
		/// <summary>
		/// Lose Focus Event:
		/// set btnState to Normal
		/// </summary>
		/// <param name="e"></param>
		protected override void OnLostFocus(EventArgs e)
		{
			base.OnLostFocus (e);
			if(this.Enabled)
			{
				this.btnState = BtnState.Normal;
			}
			this.Invalidate();
		}


#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.


Written By
Web Developer
United States United States
I've enjoyed programming for over 15 years, beginning with the commodore 64. That was an interesting time, since creating a program involved using a tool named HESMON to write hex OPCODEs directly into memory. That was the days of PEEKS, POKES, and SYS. From there, I moved to the Amiga, and eventually to the 8088. Perhaps, I should say ‘We’, since my brother and I share the same enthusiasm and worked together for a number years.

As with many others, my initial interests in programming was sparked by games. However, as time progressed, it was more lucrative to put gaming on the shelf, and move into the business world. This has led me to work with CGI, Javascript, Asp, and now the Dot Net technologies. I’ve been fortunate to work with great people creating CE, Win32 and Web applications. With that said, many of the techniques learned early on in gaming can still be useful and applied even today.

If you wish to contact me please send an e-mail to: jsimms_articles@yahoo.com

Enjoy

James

Comments and Discussions