Click here to Skip to main content
15,898,134 members
Articles / Programming Languages / C#

Blackjack - a real world OOD example

Rate me:
Please Sign up or sign in to vote.
4.87/5 (47 votes)
18 Jul 20076 min read 236.7K   9.6K   153  
Learn OOD in .NET by examining a Blackjack game
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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
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.

Comments and Discussions