using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Reflection;

//using Microsoft.VisualBasic.MyServices;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectPlay;
using Microsoft.DirectX.DirectInput;


namespace DarkStrideToolbox
{
	#region EventArg Derived Classes
	public class DSMouseWheelMoveEventArgs: EventArgs 
	{
		public DSMouseWheelMoveEventArgs(long nDirection) 
		{
			this.m_nDirection = nDirection;
		}

		private long m_nDirection;
		public long Direction
		{
			get
			{
				return( m_nDirection );
			}
		}
	}
	public class DSMouseMoveEventArgs: EventArgs 
	{
		public DSMouseMoveEventArgs(Vector2 vMousePosInControlSpace,bool[] baButtons) 
		{
			this.m_vMousePosInControlSpace = vMousePosInControlSpace;
			this.m_baButtons = baButtons;
		}

		private Vector2 m_vMousePosInControlSpace;
		private bool[] m_baButtons;
		public Vector2 MousePosInControlSpace
		{
			get
			{
				return( m_vMousePosInControlSpace );
			}
		}
		public bool[] Buttons
		{
			get
			{
				return( m_baButtons );
			}
		}				
	}
	public class DSMouseClickEventArgs: EventArgs 
	{
		public DSMouseClickEventArgs(Vector2 vMousePosInControlSpace,long nButton) 
		{
			this.m_vMousePosInControlSpace = vMousePosInControlSpace;
			this.m_nButton = nButton;
		}

		private Vector2 m_vMousePosInControlSpace;
		private long m_nButton;
		public Vector2 MousePosInControlSpace
		{
			get
			{
				return( m_vMousePosInControlSpace );
			}
		}
		public long Buttons
		{
			get
			{
				return( m_nButton );
			}
		}				
	}

	public class DSKeyEventArgs: EventArgs 
	{
		public DSKeyEventArgs(Microsoft.DirectX.DirectInput.Key oKey,bool[] oState) 
		{
			this.m_oKey = oKey;
			this.m_oState = oState;
		}

		private Microsoft.DirectX.DirectInput.Key m_oKey;
		private bool[] m_oState;
		public Microsoft.DirectX.DirectInput.Key Key
		{
			get
			{
				return( m_oKey );
			}
		}
		public bool[] State
		{
			get
			{
				return( m_oState );
			}
		}				
	}

	public class DSDragEventArgs: EventArgs 
	{
		public DSDragEventArgs(object oDragAndDropSourceControl,object oDragAndDropData) 
		{
			this.m_oDragAndDropSourceControl = oDragAndDropSourceControl;
			this.m_oDragAndDropData = oDragAndDropData;
		}

		private object m_oDragAndDropSourceControl;
		private object m_oDragAndDropData;
		public object DragAndDropSourceControl
		{
			get
			{
				return( m_oDragAndDropSourceControl );
			}
		}
		public object DragAndDropData
		{
			get
			{
				return( m_oDragAndDropData );
			}
		}				
	}
	#endregion

	#region DSForms Class
	public class DSForms
	{
		#region Properties
		protected static string m_cSEP = "[FsSep;]";

		//Added drag and drop capability
		protected object m_oDragAndDropSourceControl = null;
		protected bool m_bDragAndDropInProgress = false;
		protected object m_oDragAndDropData = null;
		protected object m_oCurrentlyDragAndDropOver = null;

		//Added mouse enter and mouse leave functions
		protected object m_oCurrentlyMovingOver = null;

		//04/02/2005 Chris Hill  If we are in debug mode we handle I/O differently.
		//		private bool m_bEditMode = false;
		//		private DSBaseControl m_oControlBeingEdited = null;
		//		private bool m_bEditMouseDownOnControl = false;
		//		private Vector2 m_oMouseDownPos = new Vector2( 0,0 );

		//This is the actual DSForm data storage
		private DSForm[] m_oaFormsInZOrder = null;
		private int m_nMaxFormSize = 50;
		private int m_nNextFreeIndex = 0;
		private int m_nCurrentMoveIndex = -1;

		//Track mouse movements so we know where focuses are and such
		private DSForm m_oFormMouseDownOn = null;

		//Keep track of who has focus
		private DSForm m_oFormWithFocus = null;

		private DSGraphicsWrapper m_oDSGraphicsWrapper = null;		
		private DSInputWrapper m_oDSInputWrapper = null;
		#endregion

		#region Event code
		public event EventHandler MouseWheelMove;
		public event EventHandler MouseDown;
		public event EventHandler MouseUp;
		public event EventHandler MouseClick;
		public event EventHandler MouseMove;
		public event EventHandler MouseEnter;
		public event EventHandler MouseLeave;
		public event EventHandler KeyUp;
		public event EventHandler KeyDown;
		protected void RaiseMouseWheelMoveEvent(DSForms oSender,long nDirection)
		{
			DSMouseWheelMoveEventArgs oArgs = null;

			if( MouseWheelMove != null )
			{
				oArgs = new DSMouseWheelMoveEventArgs( nDirection );
				MouseWheelMove( oSender, oArgs );
			}
		}
		protected void RaiseMouseDownEvent(DSForms oSender,Vector2 vMousePosInControlSpace,long nButton)
		{
			DSMouseClickEventArgs oArgs = null;

			if( MouseDown != null )
			{
				oArgs = new DSMouseClickEventArgs( vMousePosInControlSpace,nButton );
				MouseDown( oSender, oArgs );
			}
		}		
		protected void RaiseMouseUpEvent(DSForms oSender,Vector2 vMousePosInControlSpace,long nButton)
		{
			DSMouseClickEventArgs oArgs = null;

			if( MouseUp != null )
			{
				oArgs = new DSMouseClickEventArgs( vMousePosInControlSpace,nButton );
				MouseUp( oSender, oArgs );
			}
		}		
		protected void RaiseMouseClickEvent(DSForms oSender,Vector2 vMousePosInControlSpace,long nButton)
		{
			DSMouseClickEventArgs oArgs = null;

			if( MouseClick != null )
			{
				oArgs = new DSMouseClickEventArgs( vMousePosInControlSpace,nButton );
				MouseClick( oSender, oArgs );
			}
		}		
		protected void RaiseMouseMoveEvent(DSForms oSender,Vector2 vMousePosInControlSpace,bool[] baButtons)
		{
			DSMouseMoveEventArgs oArgs = null;

			if( MouseMove != null )
			{
				oArgs = new DSMouseMoveEventArgs( vMousePosInControlSpace,baButtons );
				MouseMove( oSender, oArgs );
			}
		}		

		protected void RaiseKeyUpEvent(DSForms oSender,Microsoft.DirectX.DirectInput.Key oKey,bool[] oState)
		{
			DSKeyEventArgs oArgs = null;

			if( KeyUp != null )
			{
				oArgs = new DSKeyEventArgs( oKey,oState );
				KeyUp( oSender, oArgs );
			}
		}		
		protected void RaiseKeyDownEvent(DSForms oSender,Microsoft.DirectX.DirectInput.Key oKey,bool[] oState)
		{
			DSKeyEventArgs oArgs = null;

			if( KeyDown != null )
			{
				oArgs = new DSKeyEventArgs( oKey,oState );
				KeyDown( oSender, oArgs );
			}
		}		

		protected void RaiseMouseEnterEvent(DSForms oSender,Vector2 vMousePosInControlSpace,bool[] baButtons)
		{
			DSMouseMoveEventArgs oArgs = null;

			if( MouseEnter != null )
			{
				oArgs = new DSMouseMoveEventArgs( vMousePosInControlSpace,baButtons );
				MouseEnter( oSender, oArgs );
			}
		}		
		protected void RaiseMouseLeaveEvent(DSForms oSender,Vector2 vMousePosInControlSpace,bool[] baButtons)
		{
			DSMouseMoveEventArgs oArgs = null;

			if( MouseLeave != null )
			{
				oArgs = new DSMouseMoveEventArgs( vMousePosInControlSpace,baButtons );
				MouseLeave( oSender, oArgs );
			}
		}		
		#endregion


		public DSForms( DSInputWrapper oDSInputWrapper,DSGraphicsWrapper oDSGraphicsWrapper )
		{
			m_oDSInputWrapper = oDSInputWrapper;
			m_oDSGraphicsWrapper = oDSGraphicsWrapper;
			m_oaFormsInZOrder = new DSForm[ m_nMaxFormSize ];
		}


		//Returns weather or not the mouse event was used by the DSForm.  The mouse cursor returned is the mouse cursor
		//the DSForm would like to have used.	
		public bool OnMouseDown( Vector2 vMousePosInScrSpace,long nButton )
		{
			DSForm oFormClickedOn = null;
			Vector2 vMousePosInFormSpace;
			bool bActionWasUsed = false;


			RaiseMouseDownEvent( this,vMousePosInScrSpace,nButton );

			if( bActionWasUsed == false )
			{
				//Did they click on a DSForm?  If so its either a control click or a DSForm moving
				oFormClickedOn = GetFormAt( vMousePosInScrSpace );

				//No DSForm.  Just an idle screen click.  Ignore it.
				if( oFormClickedOn == null )
				{
					m_oFormMouseDownOn = null;
					m_oFormWithFocus = null;
					bActionWasUsed = false;
				}
					//They clicked on a DSForm!  
				else
				{
					vMousePosInFormSpace = new Vector2( vMousePosInScrSpace.X - oFormClickedOn.Location.X,
						vMousePosInScrSpace.Y - oFormClickedOn.Location.Y );

					m_oFormWithFocus = oFormClickedOn;
					m_oFormMouseDownOn = oFormClickedOn;
					MoveFormToTop( oFormClickedOn.Name );

					bActionWasUsed = oFormClickedOn.OnMouseDown( vMousePosInFormSpace,nButton );
				}
			}
		
			return( bActionWasUsed );
		}
		public bool OnMouseUp( Vector2 vMousePosInScrSpace,long nButton )
		{
			bool bActionWasUsed = false;
			Vector2 vMousePosInFormSpace;


			RaiseMouseUpEvent( this,vMousePosInScrSpace,nButton );

			if( bActionWasUsed == false )
			{
				if( m_oFormMouseDownOn != null )
				{
					//12/18/2004 Chris Hill  The click location was being passsed in as screen
					//space not menuy space as we really needed it to be.
					vMousePosInFormSpace = new Vector2( vMousePosInScrSpace.X - m_oFormMouseDownOn.Location.X,
						vMousePosInScrSpace.Y - m_oFormMouseDownOn.Location.Y );
	
					bActionWasUsed = m_oFormMouseDownOn.OnMouseUp( vMousePosInFormSpace,nButton );
					m_oFormMouseDownOn = null;
				}
			}
		
			return( bActionWasUsed );
		}

		public bool OnMouseMove( Vector2 vMousePosInScrSpace,MouseState oMouseState,bool[] baButtons )
		{
			DSForm oFormMovedOver = null;
			DSBaseControl oControl = null;
			Vector2 vMousePosInFormSpace;
			bool bActionWasUsed = false;


			RaiseMouseMoveEvent( this,vMousePosInScrSpace,baButtons );

			//11/16/2004 Chris Hill  If you do a sliding click on an exit button then you can cuase the menu to 
			//call this even though most of the member variables are gone.  So just exit out.
			if( m_oaFormsInZOrder != null && bActionWasUsed == false )
			{
				//07/01/2005 Chris Hill  Actually if we are actually DragDropping then we have to switch.
				//05/14/2005 Chris Hill  If we are dragging we can't switch forms
				if( m_oFormMouseDownOn != null && m_bDragAndDropInProgress == false )
				{
					vMousePosInFormSpace = new Vector2( vMousePosInScrSpace.X - m_oFormMouseDownOn.Location.X,
						vMousePosInScrSpace.Y - m_oFormMouseDownOn.Location.Y );
					bActionWasUsed = m_oFormMouseDownOn.OnMouseMove( vMousePosInFormSpace,baButtons );
				}
				else
				{
					oFormMovedOver = GetFormAt( vMousePosInScrSpace );

					if( oFormMovedOver == null )
					{
						if( m_oCurrentlyMovingOver != null )
						{
							oControl = ((DSBaseControl)m_oCurrentlyMovingOver);
							vMousePosInFormSpace = new Vector2( vMousePosInScrSpace.X - oControl.Location.X,
								vMousePosInScrSpace.Y - oControl.Location.Y );
							bActionWasUsed = oControl.OnMouseLeave( vMousePosInFormSpace,baButtons );
						}
						else
						{
							bActionWasUsed = false;
						}

						this.DSGraphicsWrapper.TopmostForm.Cursor = Cursors.Default;
					}
					else
					{
						vMousePosInFormSpace = new Vector2( vMousePosInScrSpace.X - oFormMovedOver.Location.X,
							vMousePosInScrSpace.Y - oFormMovedOver.Location.Y );
						bActionWasUsed = oFormMovedOver.OnMouseMove( vMousePosInFormSpace,baButtons );
					}
				}
			}
		
			return( bActionWasUsed );
		}
		public bool OnMouseWheelMove( long nDirection )
		{
			bool bActionWasUsed = false;

			RaiseMouseWheelMoveEvent( this,nDirection );

			return( bActionWasUsed );
		}

		public bool OnMouseEnter( Vector2 vMousePosInScrSpace,MouseState oMouseState,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			RaiseMouseEnterEvent( this,vMousePosInScrSpace,baButtons );

			return( bActionWasUsed );
		}
		public bool OnMouseLeave( Vector2 vMousePosInScrSpace,MouseState oMouseState,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			RaiseMouseLeaveEvent( this,vMousePosInScrSpace,baButtons );

			return( bActionWasUsed );
		}
		public bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			RaiseKeyDownEvent( this,oKey,oState );

			if( m_oFormWithFocus != null && bActionWasUsed == false )
			{
				bActionWasUsed = m_oFormWithFocus.OnKeyDown( oKey,oState );
			}
		
			return( bActionWasUsed );
		}
		public bool OnKeyUp( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			RaiseKeyUpEvent( this,oKey,oState );

			if( m_oFormWithFocus != null && bActionWasUsed == false )
			{
				bActionWasUsed = m_oFormWithFocus.OnKeyUp( oKey,oState );
			}
		
			return( bActionWasUsed );
		}


		public DSForm Show( string sFormName )
		{
			return( Show( sFormName,false ) );
		}
		public DSForm Show( string sFormName,bool bHideAllOtherForms )
		{
			DSForm oRetVal = null;

			//Bring our form to the top
			MoveFormToTop( sFormName );

			//Hide all the active forms except this one
			for( int i=0 ; i<m_nNextFreeIndex ; i++ )
			{
				if( m_oaFormsInZOrder[ i ] != null )
				{
					if( m_oaFormsInZOrder[ i ].Name == sFormName )
					{
						oRetVal = m_oaFormsInZOrder[ i ];
						oRetVal.Visible = true;

						//And make sure this is the main form
						if( m_oFormWithFocus != oRetVal )
						{
							m_oFormMouseDownOn = null;
							m_oFormWithFocus = oRetVal;
						}
					}
					else if( bHideAllOtherForms == true )
					{
						m_oaFormsInZOrder[ i ].Visible = false;
					}
				}
			}

			return( oRetVal );
		}


		//Handle the maintance of our array
		public DSForm Add( string sFormName,Vector2 vPosition,Vector2 vSize,bool bIsModal )
		{
			DSForm oNewForm = null;

			oNewForm = Add( sFormName,"System_Form",vPosition,vSize,bIsModal );
		
			return( oNewForm );
		}
		public DSForm Add( string sFormName,string sFormTextureKey,Vector2 vPosition,Vector2 vSize,bool bIsModal )
		{
			DSForm oNewForm = null;

			oNewForm = new DSForm( this );

			oNewForm.Name = sFormName;
			oNewForm.Location = new Point( (int)vPosition.X,(int)vPosition.Y );
			oNewForm.Size = vSize;
			oNewForm.IsModal = bIsModal;
			oNewForm.TextureKey = sFormTextureKey;				

			//Save our work
			Add( oNewForm );

			return( oNewForm );
		}

		public void Add( DSForm oNewForm )
		{
			DSBaseControl oLoopControl = null;


			//First make sure they aren't breaking modal, non-modal rules
			if( oNewForm.IsModal == false && this.IsModalForm == true )
			{
				throw new System.Exception( "You cannot add a non-modal DSForm when their is already a modal DSForm in use. <" + oNewForm.Name + "." );
			}

			if( m_nNextFreeIndex < m_nMaxFormSize )
			{
				//Verify that all the controls have the forms reference too
				for( int i=0 ; i<oNewForm.Controls.Count ; i++ )
				{
					oLoopControl = (DSBaseControl)oNewForm.Controls.GetByIndex( i );
					oLoopControl.Forms = this;
				}

				oNewForm.Forms = this;
				oNewForm.DSGraphicsWrapper = m_oDSGraphicsWrapper;
				m_oaFormsInZOrder[ m_nNextFreeIndex++ ] = oNewForm;
			}
			else
			{
				throw new System.Exception( "Adding DSForm exceeds limit.  This functionality needs to be enhanced to dynamically grow in size." );
			}
		}
		public void Remove( string sFormName )
		{
			Remove( sFormName,false );
		}
		public void Remove( string sFormName,bool bThrowErrorIfFormIsNotFound )
		{
			int nIndex = -1;

			nIndex = GetFormIndex( sFormName );

			if( nIndex != -1 )
			{
				if( m_oaFormsInZOrder[ nIndex ] != null )
				{
					if( m_oFormWithFocus != null )
					{
						if( m_oFormWithFocus.Name.Equals( m_oaFormsInZOrder[ nIndex ].Name ) == true )
						{
							m_oFormWithFocus = null;
						}
					}

					if( m_oFormMouseDownOn != null )
					{
						if( m_oFormMouseDownOn.Name.Equals( m_oaFormsInZOrder[ nIndex ].Name ) == true )
						{
							m_oFormMouseDownOn = null;
						}
					}
				}

				m_oaFormsInZOrder[ nIndex ] = null;
			}
			else if( bThrowErrorIfFormIsNotFound == true )
			{
				throw new System.Exception( "Form named <" + sFormName + "> was not found." );
			}
		}

		public DSForm GetForm( string sFormName )
		{
			DSForm oRetForm = null;
			int nIndex = -1;

			nIndex = GetFormIndex( sFormName );
			if( nIndex != -1 )
			{
				oRetForm = m_oaFormsInZOrder[ nIndex ];
			}

			return( oRetForm );
		}
		public DSForm GetForm( long nFormIndex )
		{
			int nFormIndexWereOn = -1;
			DSForm oRetVal = null;

			for( int i=0 ; i<m_nNextFreeIndex ; i++ )
			{
				if( m_oaFormsInZOrder[ i ] != null )
				{
					nFormIndexWereOn++;
					if( nFormIndexWereOn == nFormIndex )
					{
						oRetVal = m_oaFormsInZOrder[ i ];
					}
				}
			}

			return( oRetVal );
		}
		public int GetFormIndex( string sFormName )
		{
			int nFormIndex = -1;

			if( sFormName == null )
			{
				//02/19/2005 Chris Hill  If you pass in a null name then throw an error.
				throw new System.Exception( "Form names can't be null." );
			}
			else
			{
				for( int i=0 ; i<m_nNextFreeIndex ; i++ )
				{
					if( m_oaFormsInZOrder[ i ] != null )
					{
						if( m_oaFormsInZOrder[ i ].Name.Equals( sFormName ) == true )
						{
							nFormIndex = i;
							break;
						}
					}
				}

				/*if( nFormIndex == -1 )
					{
						throw new System.Exception( "Unable to locate DSForm <" + sFormName + ">" );
					}*/
			}

			return( nFormIndex );
		}

		public DSForm GetFormAt( Vector2 vMouseClickInScrSpace )
		{
			DSForm oForm = null;
			DSForm oRetVal = null;

			for( int i=m_nNextFreeIndex ; i>=0 ; i-- )
			{
				oForm = m_oaFormsInZOrder[ i ];
				if( oForm != null && oForm.Visible == true )
				{
					//02/16/2006 Chris Hill  Now let forms be varying sizes.
					if( oForm.ContainsPoint( new Point( (int)vMouseClickInScrSpace.X,(int)vMouseClickInScrSpace.Y ) ) == true )
						//if( vMouseClickInScrSpace.X >= oForm.Location.X && vMouseClickInScrSpace.Y >= oForm.Location.Y &&
						//	vMouseClickInScrSpace.X <= oForm.Location.X + oForm.Size.X &&
						//	vMouseClickInScrSpace.Y <= oForm.Location.Y + oForm.Size.Y )
					{
						oRetVal = oForm;
						break;
					}
						//If this form is modal we can't go any lower... so no click was registered
					else if( oForm.IsModal == true )
					{
						break;
					}
				}
			}

			return( oRetVal );
		}

		public void MoveFormToTop( string sFormName )
		{
			int nIndex = -1;


			nIndex = GetFormIndex( sFormName );

			if( nIndex != -1 )
			{
				m_oaFormsInZOrder[ m_nNextFreeIndex++ ] = m_oaFormsInZOrder[ nIndex ];
				m_oaFormsInZOrder[ nIndex ] = null;

				ReShuffleZOrders();
			}
			else
			{
				throw new System.Exception( "Unable to find form with the name <" + sFormName + ">." );
			}
		}

		private void ReShuffleZOrders()
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.ReShuffleZOrders";
			bool bReplacementDone = false;

			try
			{
				for( int i=0 ; i<m_nNextFreeIndex ; i++ )
				{
					if( m_oaFormsInZOrder[ i ] == null )
					{
						//Now find the next non-null DSForm spot
						bReplacementDone = false;
						for( int nNextUsedSpot=i+1 ; nNextUsedSpot<m_nNextFreeIndex ; nNextUsedSpot++ )
						{
							if( m_oaFormsInZOrder[ nNextUsedSpot ] != null )
							{
								bReplacementDone = true;
								m_oaFormsInZOrder[ i ] = m_oaFormsInZOrder[ nNextUsedSpot ];
								m_oaFormsInZOrder[ nNextUsedSpot ] = null;
								break;
							}
						}

						//If we didn't do a replacement then the next free spot gets moved up
						if( bReplacementDone == false )
						{
							m_nNextFreeIndex = i;
							break;
						}
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		private void ReDimArray()
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.ReDimArray";
			DSForm[] oaTempStorage = null;

			try
			{
				//Create a new array
				m_nMaxFormSize = m_nMaxFormSize * 2;
				oaTempStorage = new DSForm[ m_nMaxFormSize ];
				
				//Now copy over our data
				for( int i=0 ; i<m_nNextFreeIndex ; i++ )
				{
					oaTempStorage[ i ] = m_oaFormsInZOrder[ i ];
				}

				//And finally copy over our new array
				m_oaFormsInZOrder = oaTempStorage;
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

		private int GetHighestFormIndex()
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.GetHighestFormIndex";
			int nRetVal = 0;

			try
			{
				//Chris
				//				m_bIsModalForm = IsModalForm();

				for( int nIndex=m_nNextFreeIndex-1 ; nIndex>0 ; nIndex-- )
				{
					if( m_oaFormsInZOrder[ nIndex ] != null )
					{
						nRetVal = nIndex;
						break;
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( nRetVal );
		}

		public bool PointCanBeClickedOn( DSForm oForm,Vector2 vScreenPoint )
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.PointCanBeClickedOn";
			int nMyIndex = 0;
			bool bCanBeClickedOn = true;

			try
			{
				//First of all find me in the array o' menus
				nMyIndex = GetFormIndex( oForm.Name );

				//Now walk up the list 
				for( int nIndex=nMyIndex+1 ; nIndex<m_nNextFreeIndex ; nIndex++ )
				{
					if( m_oaFormsInZOrder[ nIndex ] != null )
					{
						//Is the point within the range of the menus above us?  If so then we can't click on it
						if( vScreenPoint.X >= m_oaFormsInZOrder[ nIndex ].Location.X && vScreenPoint.X <= m_oaFormsInZOrder[ nIndex ].Location.X+m_oaFormsInZOrder[ nIndex ].Size.X && 
							vScreenPoint.Y >= m_oaFormsInZOrder[ nIndex ].Location.Y && vScreenPoint.Y <= m_oaFormsInZOrder[ nIndex ].Location.Y+m_oaFormsInZOrder[ nIndex ].Size.Y )
						{
							bCanBeClickedOn = false;
							break;
						}
							//But their is more... is their a modal form above us?  If so it can't be clicked on
						else if( m_oaFormsInZOrder[ nIndex ].IsModal == true )
						{
							bCanBeClickedOn = false;
							break;
						}
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( bCanBeClickedOn );
		}

		public void SetFormFocus( DSForm oForm )
		{
			MoveFormToTop( oForm.Name );
			m_oFormWithFocus = oForm;
		}

		public void DoDragDrop( DSForm oForm,object oData )
		{
			this.DragAndDropInProgress = true;
			this.DragAndDropData = oData;
			this.CurrentlyDragAndDropOver = oForm;
			this.DragAndDropSourceControl = oForm;
			m_oFormWithFocus = oForm;
			m_oFormMouseDownOn = oForm;
		}


		//This of course is where we render the DSForm from 
		public void Render()
		{
			for( int nIndex=0 ; nIndex<m_nNextFreeIndex ; nIndex++ )					
			{
				if( m_oaFormsInZOrder[ nIndex ] != null )
				{
					m_oaFormsInZOrder[ nIndex ].Render();
				}
			}
		}

		public string GetCurrentCursorTextureKey( Vector2 vMousePosInScrSpace )
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.GetCurrentCursorTextureKey";
			DSForm oFormMouseOver = null;
			Vector2 vMousePosInFormSpace;
			string sRetVal = "";

			try
			{
				oFormMouseOver = GetFormAt( vMousePosInScrSpace );

				if( oFormMouseOver != null )
				{
					vMousePosInFormSpace = new Vector2( vMousePosInScrSpace.X - oFormMouseOver.Location.X,
						vMousePosInScrSpace.Y - oFormMouseOver.Location.Y );
					sRetVal = oFormMouseOver.GetCurrentCursorTextureKey( vMousePosInFormSpace );
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}

		public void FrameMove( double dElapsedTime,double dAppTime )
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.FrameMove";
			string shi = "";
			try
			{
				for( int nIndex=0 ; nIndex<m_nNextFreeIndex ; nIndex++ )
				{
					if( m_oaFormsInZOrder[ nIndex ] != null )
					{
						shi = "1;" + nIndex.ToString();
						m_oaFormsInZOrder[ nIndex ].FrameMove( dElapsedTime,dAppTime );
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}

		public virtual void Dispose()
		{
			const string sRoutineName = "DarkStrideToolbox.DSForm.Dispose";

			try
			{
				m_oFormMouseDownOn = null;
				m_oFormWithFocus = null;

				for( int i=m_nNextFreeIndex ; i>=0 ; i-- )
				{
					if( m_oaFormsInZOrder[ i ] != null )
					{
						m_oaFormsInZOrder[ i ].Dispose();
						m_oaFormsInZOrder[ i ] = null;
					}
				}

				m_oaFormsInZOrder = null;
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}


		public virtual void LoadFromStream( System.IO.Stream oStream )
		{
			LoadFromStream( oStream,"" );
		}
		public virtual void LoadFromStream( System.IO.Stream oStream,string sFormName )
		{
			DSForm oForm = null;
			string[] saParsed = null;
			string[] saLines = null;
			string sFile = "";
			byte[] baFile = null;
			object[] oaArguments = null;
			Assembly oFormAssembly = null;
			Type oFormType = null;
			char cChar;


			//Load in our file from the stream
			baFile = new byte[ (int)oStream.Length ];
			oStream.Read( baFile,0,(int)oStream.Length );
			//We shoulden't have to do this, but obviously I still don't understand how to convert properly to and from by arrays.
			for( long i=0 ; i<baFile.Length ; i++ )
			{
				cChar = Convert.ToChar( baFile[ i ] );
				sFile += cChar.ToString();
			}


			//Now break it up and walk through all the lines
			saLines = DSMisc.Split( sFile,"\r\n" );
			for( long i=0 ; i<saLines.Length-1 ; i++ )
			{
				saParsed = DSMisc.Split( saLines[ i ],m_cSEP );

				//Deserialize the form into a new object... so first create the new object
				oFormAssembly = Assembly.LoadWithPartialName( saParsed[ 1 ] );
				oFormType = oFormAssembly.GetType( saParsed[ 1 ] + "." + saParsed[ 0 ] );
				//Prepare arguments
				oaArguments = new object[ 1 ];
				oaArguments[ 0 ] = this;
				//Make it!
				oForm = (DSForm)Activator.CreateInstance( oFormType,oaArguments );
				//Now deserialize the form
				oForm.DeSerialize( saParsed[ 2 ] );
				oForm.Visible = false;


				//Do we add this form?
				if( sFormName == oForm.Name || sFormName.Length == 0)
				{
					//Does this form exist yet?  If so then remove it first
					if( GetForm( oForm.Name ) != null )
					{
						//This means it does exist, so remove it first.
						Remove( oForm.Name );
					}

					//Now add it
					Add( oForm );
				}
			}

			oStream.Close();
		}
		public virtual void LoadFromFile( string sFileName )
		{
			LoadFromFile( sFileName,"" );
		}
		public virtual void LoadFromFile( string sFileName,string sFormName )
		{
			StreamReader oStream = null;

			//Open our input file
			oStream = new StreamReader( sFileName );
			LoadFromStream( oStream.BaseStream,sFormName );
		}

		public virtual void SaveToFile( string sFileName,bool bAppendIfFileExists )
		{
			SaveToFile( sFileName,bAppendIfFileExists,"" );
		}
		public virtual void SaveToFile( string sFileName,bool bAppendIfFileExists,string sFormName )
		{
			StreamWriter oStream = null;
			DSForm oForm = null;
			string sForm = "";


			try
			{
				//Open the file
				oStream = new StreamWriter( sFileName,bAppendIfFileExists );

				//Dump the data
				for( int nFormIndex=0 ; nFormIndex<m_oaFormsInZOrder.Length-1 ; nFormIndex++ )
				{
					oForm = m_oaFormsInZOrder[ nFormIndex ];

					if( oForm != null )
					{
						//Is this a form we want to save?
						if( sFormName == oForm.Name || sFormName.Length == 0 )
						{
							//Write header information
							sForm = oForm.GetType().Name + m_cSEP + 
								oForm.GetType().Namespace + m_cSEP + 
								oForm.Serialize() + m_cSEP;

							oStream.WriteLine( sForm );
						}
					}
				}

				oStream.Close();
			}
			catch( System.Exception oEx )
			{
				//Clean up after our selves
				if( oStream != null )
				{
					oStream.Close();
				}
				throw new System.Exception( oEx.Message );
			}
		}


		//Navigation Functions
		public void MoveFirst()
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.MoveFirst";

			try
			{
				m_nCurrentMoveIndex = -1;

				for( int i=0 ; i<m_nNextFreeIndex ; i++ )
				{
					if( m_oaFormsInZOrder[ i ] != null )
					{
						m_nCurrentMoveIndex = i;
						break;
					}
				}				
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public void MoveNext()
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.MoveNext";
			int i = -1;

			try
			{
				i = m_nCurrentMoveIndex + 1;
				m_nCurrentMoveIndex = -1;
				for( ; i<m_nNextFreeIndex ; i++ )
				{
					if( m_oaFormsInZOrder[ i ] != null )
					{
						m_nCurrentMoveIndex = i;
						break;
					}
				}		
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}
		public DSForm GetItem()
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.GetItem";
			DSForm oRetForm = null;

			try
			{
				if( GetEOF() == false )
				{
					oRetForm = m_oaFormsInZOrder[ m_nCurrentMoveIndex ];
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( oRetForm );
		}
		public bool GetEOF()
		{
			const string sRoutineName = "DarkStrideToolbox.Forms.GetEOF";
			bool bEOF = false;

			try
			{
				bEOF = ( m_nCurrentMoveIndex == -1 );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( bEOF );
		}

		public long Count
		{
			get
			{
				const string sRoutineName = "DarkStrideToolbox.Forms.get_Count";
				long nCount = 0;

				try
				{				
					for( int i=0 ; i<m_nNextFreeIndex ; i++ )
					{
						if( m_oaFormsInZOrder[ i ] != null )
						{
							nCount++;
						}
					}				
				}
				catch( System.Exception oEx )
				{
					throw new System.Exception( sRoutineName + " Failed.",oEx );
				}

				return( nCount );
			}
		}



		#region Properties
		public bool IsModalForm
		{
			get
			{
				const string sRoutineName = "DarkStrideToolbox.Forms.IsModalForm";
				DSForm oForm = null;
				bool bRetVal = false;

				try
				{
					for( int i=0 ; i<m_nNextFreeIndex ; i++ )
					{
						oForm = m_oaFormsInZOrder[ i ];
						if( oForm != null )
						{
							if( oForm.IsModal == true && oForm.Visible == true )
							{
								bRetVal = true;
								break;
							}
						}
					}
				}
				catch( System.Exception oEx )
				{
					throw new System.Exception( sRoutineName + " Failed.",oEx );
				}

				return( bRetVal );
			}
		}
		public DSForm FormWithFocus
		{
			get
			{
				return( m_oFormWithFocus );
			}
		}
		public object DragAndDropSourceControl
		{
			get
			{
				return( m_oDragAndDropSourceControl );
			}
			set
			{
				m_oDragAndDropSourceControl = value;
			}
		}
		public object CurrentlyDragAndDropOver
		{
			get
			{
				return( m_oCurrentlyDragAndDropOver );
			}
			set
			{
				m_oCurrentlyDragAndDropOver = value;
			}
		}
		public bool DragAndDropInProgress
		{
			get
			{
				return( m_bDragAndDropInProgress );
			}
			set
			{
				m_bDragAndDropInProgress = value;
			}
		}
		public object DragAndDropData
		{
			get
			{
				return( m_oDragAndDropData );
			}
			set
			{
				m_oDragAndDropData = value;
			}
		}
		public object CurrentlyMovingOver
		{
			get
			{
				return( m_oCurrentlyMovingOver );
			}
			set
			{
				m_oCurrentlyMovingOver = value;
			}
		}
		public DSForm[] FormsInZOrder
		{
			get
			{
				return( m_oaFormsInZOrder );
			}
		}
		public DSInputWrapper DSInputWrapper
		{
			get
			{
				return( m_oDSInputWrapper );
			}
		}
		public DSGraphicsWrapper DSGraphicsWrapper
		{
			get
			{
				return( m_oDSGraphicsWrapper );
			}
		}
		#endregion
	};
	#endregion
    
	#region DSForm Class
	public class DSForm : DSBaseControl
	{
		#region Properties
		protected static string m_cFORMSEP = "[FSep;]";
		protected static string m_cCTRLSEP = "[FCSep;]";
		protected static string m_cVERSION = "Version1.0";
		protected static new string m_cVERSION_20 = "Version2.0";

		public static readonly ColorValue WhiteColorValue = new ColorValue(1.0f, 1.0f, 1.0f, 1.0f); 
		public static readonly ColorValue TransparentWhite = new ColorValue(1.0f, 1.0f, 1.0f, 0.0f); 
		public static readonly ColorValue BlackColorValue = new ColorValue(0.0f, 0.0f, 0.0f, 1.0f); 

		private string m_sTextureKey;
		private bool m_bIsModal;
		private bool m_bCanBeDragged;		
		private string m_sText = "";

		//If the user sets the size we don't want to overrule their setting.
		private bool m_bUserSetLocation = false;

		//If during the OnResize event you try to change the size of the form an infite loop
		//occurs.  To avoid this, this variable tells us if we are already in the OnResize and
		//if we are then we avoid calling it again.
		private bool m_bInOnResize = false;

		//Collection of the controls on this form
		private SortedList m_oControls = new SortedList();

		//Mouse control things
		private Vector2 m_vFormDraggingPoint;
		private Vector2 m_vFormDraggingToLowerRightDiff;
		private bool m_bBeingDragged = false;
		private bool m_bBeingResized = false;
		private DSBaseControl m_oControlMouseDownOn = null;

		//Focus management
		private DSBaseControl m_oControlWithFocus = null;

		private bool m_bHaveInitedForm = false;
		private System.Windows.Forms.FormStartPosition m_nFormStartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;

		//02/20/2006 Chris Hill  When you resize I need to know what the old size was.
		private Vector2 m_vPreResizeSize = Vector2.Empty;
		#endregion

		#region Events
		//02/25/2006 Chris Hill  Turns out sometimes you need to render things differently.
		public event EventHandler RenderPostEvent;
		public event EventHandler RenderPreEvent;
		//02/25/2006 Chris Hill  Turns out sometimes you need to render things differently.
		protected void RaiseRenderPostEvent(DSBaseControl oSender)
		{
			EventArgs oArgs = null;

			if( RenderPostEvent != null )
			{
				oArgs = new EventArgs();
				RenderPostEvent( oSender, oArgs );
			}
		}		
		protected void RaiseRenderPreEvent(DSBaseControl oSender)
		{
			EventArgs oArgs = null;

			if( RenderPreEvent != null )
			{
				oArgs = new EventArgs();
				RenderPreEvent( oSender, oArgs );
			}
		}		

		#endregion


		public DSForm( DSForms oForms )
		{
			m_oForms = oForms;
		}


		public DSButton	AddControl_Button( string sControlName,System.Drawing.Point oLocation,Vector2 vSize,string sText )
		{
			const string sRoutineName = "DarkStrideToolbox.DSForm.AddControl_Button";
			DSButton oNewCtrl = null;

			try
			{
				// First create the button
				oNewCtrl = new DSButton(m_oForms,this);

				// Set the properties of the button now
				oNewCtrl.Label = sText;
				oNewCtrl.Location = oLocation;
				oNewCtrl.Size = vSize;
				oNewCtrl.Visible = true;

				AddControl( oNewCtrl,sControlName,oLocation,vSize );
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( oNewCtrl );
		}
		public DSLabel AddControl_Label( string sControlName,System.Drawing.Point oLocation,Vector2 vSize,string sText )
		{
			DSLabel oNewCtrl = null;


			// First create the button
			oNewCtrl = new DSLabel( m_oForms,this );

			// Set the properties of the button now
			oNewCtrl.Label = sText;
			oNewCtrl.Location = oLocation;
			oNewCtrl.Size = vSize;
			oNewCtrl.Visible = true;

			AddControl( oNewCtrl,sControlName,oLocation,vSize );

			return( oNewCtrl );
		}

		public DSCheckBox AddControl_CheckBox( string sControlName,System.Drawing.Point oLocation,Vector2 vSize,string sText )
		{
			DSCheckBox oNewCtrl = null;


			// First create the button
			oNewCtrl = new DSCheckBox( m_oForms,this );

			// Set the properties of the button now
			oNewCtrl.Label = sText;
			oNewCtrl.Location = oLocation;
			oNewCtrl.Size = vSize;
			oNewCtrl.Visible = true;

			AddControl( oNewCtrl,sControlName,oLocation,vSize );

			return( oNewCtrl );
		}

		public DSRadioButton AddControl_RadioButton( string sControlName,int nGroup,System.Drawing.Point oLocation,Vector2 vSize,string sText )
		{
			DSRadioButton oNewCtrl = null;


			// First create the button
			oNewCtrl = new DSRadioButton( m_oForms,this );

			// Set the properties of the button now
			oNewCtrl.Label = sText;
			oNewCtrl.Location = oLocation;
			oNewCtrl.Size = vSize;
			oNewCtrl.Visible = true;
			oNewCtrl.ButtonGroup = nGroup;

			AddControl( oNewCtrl,sControlName,oLocation,vSize );

			return( oNewCtrl );
		}

		public DSComboBox AddControl_ComboBox( string sControlName,System.Drawing.Point oLocation,Vector2 vSize,string sText )
		{
			DSComboBox oNewCtrl = null;


			// First create the button
			oNewCtrl = new DSComboBox( m_oForms,this );

			// Set the properties of the button now
			oNewCtrl.Location = oLocation;
			oNewCtrl.Size = vSize;
			oNewCtrl.Visible = true;

			AddControl( oNewCtrl,sControlName,oLocation,vSize );

			return( oNewCtrl );
		}

		public DSSlider AddControl_Slider( string sControlName,System.Drawing.Point oLocation,Vector2 vSize )
		{
			DSSlider oNewCtrl = null;


			// First create the button
			oNewCtrl = new DSSlider( m_oForms,this );

			// Set the properties of the button now
			oNewCtrl.Location = oLocation;
			oNewCtrl.Size = vSize;
			oNewCtrl.Visible = true;

			AddControl( oNewCtrl,sControlName,oLocation,vSize );

			return( oNewCtrl );
		}
		public DSListBox AddControl_ListBox( string sControlName,System.Drawing.Point oLocation,Vector2 vSize,ListBoxStyle m_oStyle )
		{
			DSListBox oNewCtrl = null;


			// First create the button
			oNewCtrl = new DSListBox( m_oForms,this );

			// Set the properties of the button now
			oNewCtrl.Location = oLocation;
			oNewCtrl.Size = vSize;
			oNewCtrl.Visible = true;
			oNewCtrl.Style = m_oStyle;

			AddControl( oNewCtrl,sControlName,oLocation,vSize );

			return( oNewCtrl );
		}

		public DSEditBox AddControl_EditBox( string sControlName,System.Drawing.Point oLocation,Vector2 vSize,string sText )
		{
			DSEditBox oNewCtrl = null;


			// First create the button
			oNewCtrl = new DSEditBox( m_oForms,this );

			// Set the properties of the button now
			oNewCtrl.Location = oLocation;
			oNewCtrl.Size = vSize;
			oNewCtrl.Visible = true;
			oNewCtrl.Text = sText;

			AddControl( oNewCtrl,sControlName,oLocation,vSize );

			return( oNewCtrl );
		}


		public DSBaseControl AddControl( DSBaseControl oNewCtrl,string sControlName,System.Drawing.Point oLocation,Vector2 vSize )
		{
			oNewCtrl.Name = sControlName;
			oNewCtrl.Location = oLocation;
			oNewCtrl.Size = vSize;
			oNewCtrl.Forms = m_oForms;
			oNewCtrl.Form = this;

			AddControl( oNewCtrl );

			return( oNewCtrl );
		}
		public DSBaseControl AddControl( DSBaseControl oNewCtrl )
		{
			oNewCtrl.DSGraphicsWrapper = m_oDSGraphicsWrapper;
			m_oControls.Add( oNewCtrl.Name,oNewCtrl );
			oNewCtrl.OnInitialize();
			oNewCtrl.OnResize();
			oNewCtrl.Forms = m_oForms;

			return( oNewCtrl );
		}

		public void RemoveControl( string sControlName )
		{
			m_oControls.Remove( sControlName );
		}
		
		public DSBaseControl GetControlAt( Vector2 vMousePosInFormSpace )
		{
			const string sRoutineName = "DarkStrideToolbox.DSForm.GetControlAt";
			DSBaseControl oControl = null;
			DSBaseControl oRetVal = null;

			try
			{
				if( m_oControls != null )
				{
					for( int i=0 ; i<m_oControls.Count ; i++ )
					{
						oControl = (DSBaseControl)m_oControls.GetByIndex( i );
						if( oControl != null )
						{
							if( oControl.ContainsPoint( new Point( (int)vMousePosInFormSpace.X,(int)vMousePosInFormSpace.Y ) ) == true &&
								oControl.Visible == true )
							{
								oRetVal = oControl;
								break;
							}
						}
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( oRetVal );
		}

		public DSBaseControl GetControl( string sControlName )
		{
			const string sRoutineName = "DarkStrideToolbox.DSForm.GetControl";
			DSBaseControl oControl = null;
			DSBaseControl oRetVal = null;

			try
			{
				for( int i=0 ; i<m_oControls.Count ; i++ )
				{
					oControl = (DSBaseControl)m_oControls.GetByIndex( i );
					if( oControl != null )
					{
						if( oControl.Name.Equals( sControlName ) == true )
						{
							oRetVal = oControl;
							break;
						}
					}
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( oRetVal );
		}


		public void SetFocus( DSBaseControl oControlToFocusOn )
		{
			m_oControlWithFocus = oControlToFocusOn;
		}

		public override void SetFocus()
		{
			m_oForms.SetFormFocus( this );
		}

		public void ImplimentsForm( DSForm oFormToImpliment )
		{
			DSBaseControl oNewControl = null;


			//02/21/2006 Chris Hill  Its important to note that all size changes must happen
			//prior to the controls being set otherwise any anchor controled controls will
			//get shifted out of position.
			this.Size = oFormToImpliment.Size;
			this.Location = oFormToImpliment.Location;
			this.Text = oFormToImpliment.Text;
			this.GobBorderKey = oFormToImpliment.GobBorderKey;

			foreach( DSBaseControl oLoopControl in oFormToImpliment.Controls.GetValueList() )
			{
				oNewControl = oLoopControl.Copy();
				oNewControl.Form = this;
				oNewControl.Forms = this.Forms;
				this.AddControl( oNewControl );
			}
		}


		//Draw the form!
		public override void Render()
		{
			DSBaseControl oLoopBaseCtrl = null;


			if( m_bVisible == true )
			{
				if( m_bHaveInitedForm == false )
				{
					this.Form = this;
					OnInitialize();			
					OnResize();
					m_bHaveInitedForm = true;
				}

				base.Render();

				//02/25/2006 Chris Hill  Turns out sometimes you need to render things differently.
				RaiseRenderPreEvent( this );

				//Chris
				/*Rectangle oRect = new Rectangle( (int)this.Location.X,(int)this.Location.Y,
													 (int)this.Size.X,(int)this.Size.Y );
					this.DSGraphicsWrapper.RenderRectangle( oRect,Microsoft.DirectX.Direct3D.ColorValue.FromColor( System.Drawing.Color.White ) );
					this.DSGraphicsWrapper.RenderTexture2D( "System_NoTexture",new System.Drawing.Rectangle(0,0,1,1),oRect,
															new Vector2(0,0),0,0,false,System.Drawing.Color.White );*/

				//12/22/2004 Chris Hill  If we use an enumeration we can't add to the list.
				for( int i=0 ; i<m_oControls.Count ; i++ )
				{
					oLoopBaseCtrl = (DSBaseControl)m_oControls.GetByIndex( i );
					oLoopBaseCtrl.Render();
				}

				//02/25/2006 Chris Hill  Turns out sometimes you need to render things differently.
				RaiseRenderPostEvent( this );
			}
		}

		public override string GetCurrentCursorTextureKey( Vector2 vMousePosInFormSpace )
		{
			const string sRoutineName = "DarkStrideToolbox.DSForm.GetCurrentCursorTextureKey";
			DSBaseControl oControlMouseOver = null;
			Vector2 vMousePosInControlSpace;
			Vector2 vLocation;
			string sRetVal = "";

			try
			{
				oControlMouseOver = GetControlAt( vMousePosInFormSpace );

				if( oControlMouseOver != null )
				{
					vLocation = new Vector2( oControlMouseOver.Location.X,oControlMouseOver.Location.Y );
					vMousePosInControlSpace = vMousePosInFormSpace - vLocation;
					sRetVal = oControlMouseOver.GetCurrentCursorTextureKey( vMousePosInControlSpace );
				}
				else
				{
					sRetVal = this.MouseCursorTextureKey;
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}

			return( sRetVal );
		}

		public override void FrameMove( double dElapsedTime,double dAppTime )
		{
			const string sRoutineName = "DarkStrideToolbox.DSForm.FrameMove";
			Vector2 vGap = new Vector2( 1,1 );
			Vector2 vStart = new Vector2( 0,0 );
			DSBaseControl oLoopBaseCtrl = null;

			try
			{
				if( m_bHaveInitedForm == false )
				{
					this.Form = this;
					OnInitialize();			
					OnResize();
					//Note, this must be after the onresize otherwise you get an infinite loop.
					m_bHaveInitedForm = true;
				}

				base.FrameMove( dElapsedTime,dAppTime );

				//12/22/2004 Chris Hill  If we use an enumeration we can't add to the list.
				//Now render all our controls
				for( int i=0 ; i<m_oControls.Count ; i++ )
					//foreach( DSBaseControl oLoopBaseCtrl in m_oControls.GetValueList() )
				{
					oLoopBaseCtrl = (DSBaseControl)m_oControls.GetByIndex( i );
					oLoopBaseCtrl.FrameMove( dElapsedTime,dAppTime );
				}
			}
			catch( System.Exception oEx )
			{
				throw new System.Exception( sRoutineName + " Failed.",oEx );
			}
		}


		//02/18/2005 Chris Hill  Usefull for initializing things.
		public override void OnInitialize()
		{
			//If the user sets the size we would step on it.  SO this bool tells us that they
			//haven't set the size so we know were safe to.
			if( m_bUserSetLocation == false )
			{
				if( m_nFormStartPosition == System.Windows.Forms.FormStartPosition.CenterParent )
				{
					throw new System.Exception( "Form startup positions of <WindowsDefaultBounds> have not yet been implimented for this form <" + this.Name + ">" );
				}
				else if( m_nFormStartPosition == System.Windows.Forms.FormStartPosition.CenterScreen )
				{
					long nX = 0, nY = 0;

					nX = (long)(( this.DSGraphicsWrapper.Direct3DDevice.PresentationParameters.BackBufferWidth -
						this.Size.X ) / 2.0f );
					nY = (long)( ( this.DSGraphicsWrapper.Direct3DDevice.PresentationParameters.BackBufferHeight -
						this.Size.Y ) / 2.0f );
					this.Location = new Point( (int)DSMisc.Max( 0,nX ),(int)DSMisc.Max( 0,nY ) );
					//The purpose of this is to force a resize event during init no matter what.
					this.Size = this.Size;
				}
				else if( m_nFormStartPosition == System.Windows.Forms.FormStartPosition.Manual )
				{
					this.Location = new Point( 0,0 );
				}
				else if( m_nFormStartPosition == System.Windows.Forms.FormStartPosition.WindowsDefaultBounds )
				{
					throw new System.Exception( "Form startup positions of <WindowsDefaultBounds> have not yet been implimented for this form <" + this.Name + ">" );
				}
				else if( m_nFormStartPosition == System.Windows.Forms.FormStartPosition.WindowsDefaultLocation )
				{
					throw new System.Exception( "Form startup positions of <WindowsDefaultLocation> have not yet been implimented for this form <" + this.Name + ">" );
				}
			}
		}

		public override void OnResize()
		{
			DSBaseControl oLoopBaseCtrl = null;
			float nTargetWidth = 0, nTargetHeight = 0;
			float nTargetX = 0, nTargetY = 0;


			for( int i=0 ; i<m_oControls.Count ; i++ )
			{
				oLoopBaseCtrl = (DSBaseControl)m_oControls.GetByIndex( i );

				//02/20/2006 Chris Hill  Respect the anchor property now.
				if( ( oLoopBaseCtrl.Anchor & System.Windows.Forms.AnchorStyles.Left ) == System.Windows.Forms.AnchorStyles.Left &&
					( oLoopBaseCtrl.Anchor & System.Windows.Forms.AnchorStyles.Right ) == System.Windows.Forms.AnchorStyles.Right )
				{
					nTargetWidth = oLoopBaseCtrl.Size.X + ( this.Size.X - m_vPreResizeSize.X );
					nTargetX = oLoopBaseCtrl.Location.X;
				}
				else if( ( oLoopBaseCtrl.Anchor & System.Windows.Forms.AnchorStyles.Right ) == System.Windows.Forms.AnchorStyles.Right )
				{
					nTargetWidth = oLoopBaseCtrl.Size.X;
					nTargetX = oLoopBaseCtrl.Location.X + ( this.Size.X - m_vPreResizeSize.X );
				}
				else
				{
					nTargetX = oLoopBaseCtrl.Location.X;
					nTargetWidth = oLoopBaseCtrl.Size.X;
				}
				if( ( oLoopBaseCtrl.Anchor & System.Windows.Forms.AnchorStyles.Top ) == System.Windows.Forms.AnchorStyles.Top &&
					( oLoopBaseCtrl.Anchor & System.Windows.Forms.AnchorStyles.Bottom ) == System.Windows.Forms.AnchorStyles.Bottom )
				{
					nTargetHeight = oLoopBaseCtrl.Size.Y + ( this.Size.Y - m_vPreResizeSize.Y );
					nTargetY = oLoopBaseCtrl.Location.Y;
				}
				else if( ( oLoopBaseCtrl.Anchor & System.Windows.Forms.AnchorStyles.Bottom ) == System.Windows.Forms.AnchorStyles.Bottom )
				{
					nTargetHeight = oLoopBaseCtrl.Size.Y;
					nTargetY = oLoopBaseCtrl.Location.Y + ( this.Size.Y - m_vPreResizeSize.Y );
				}
				else
				{
					nTargetY = oLoopBaseCtrl.Location.Y;
					nTargetHeight = oLoopBaseCtrl.Size.Y;
				}

				//Save our selections
				if( m_vPreResizeSize != Vector2.Empty )
				{
					oLoopBaseCtrl.Size = new Vector2( nTargetWidth,nTargetHeight );
					oLoopBaseCtrl.Location = new Point( (int)nTargetX,(int)nTargetY );
				}

				oLoopBaseCtrl.OnResize();
			}
		}
					  
		public virtual void OnMoving()
		{
		}
		public virtual void OnMoved()
		{
		}


		//06/28/2005 Chris Hill  Adding drag-and-drop capability.
		public override void DoDragDrop( object oData )
		{
			m_oForms.DoDragDrop( this,oData );
		}
		public override void OnDragOver()
		{
			RaiseDragOverEvent( this );
		}
		public override void OnDragLeave()
		{
			RaiseDragLeaveEvent( this );
		}
		public override void OnDragEnter()
		{
			RaiseDragEnterEvent( this );
		}
		public override void OnDragDrop()
		{
			m_oForms.DragAndDropInProgress = false;
			RaiseDragDropEvent( this );
		}


		//This is the mouse events that users can override.  It would be unwise for a user to override these calls and
		//then not call the base class.  Some things like focus and dragging would cease to work.
		public override bool OnMouseDown( Vector2 vMousePosInFormSpace,long nButton )
		{
			bool bActionWasUsed = false;
			Vector2 vMousePosInControlSpace;
			Vector2 vLocation;

			if( m_bVisible == true )
			{
				m_oControlMouseDownOn = GetControlAt( vMousePosInFormSpace );

				RaiseMouseDownEvent( this,vMousePosInFormSpace,nButton );

				if( m_oControlMouseDownOn == null && bActionWasUsed == false )
				{
					//05/13/2005 Chris Hill  Depending on where they clicked we may be dragging
					//or we may be resizing there form.
					if( this.IsResizeHotSpot( vMousePosInFormSpace ) == true )
					{
						m_bBeingResized = true;
					}
					else if( this.IsMoveHotSpot( vMousePosInFormSpace ) == true )
					{
						m_bBeingDragged = true;
					}
					m_vFormDraggingToLowerRightDiff = this.Size - vMousePosInFormSpace;
					m_vFormDraggingPoint = vMousePosInFormSpace;
					SetFocus( null );
					bActionWasUsed = true;
				}
				else if( bActionWasUsed == false && m_bEnabled == true )
				{
					SetFocus( m_oControlMouseDownOn );
					vLocation = new Vector2( m_oControlMouseDownOn.Location.X,m_oControlMouseDownOn.Location.Y );
					vMousePosInControlSpace = vMousePosInFormSpace - vLocation;
					m_oControlMouseDownOn.OnMouseDown( vMousePosInControlSpace,nButton );

					bActionWasUsed = true;
				}
			}
		
			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInFormSpace,long nButton )
		{
			bool bActionWasUsed = false;
			Vector2 vMousePosInControlSpace;
			Vector2 vLocation;


			if( m_bVisible == true )
			{
				RaiseMouseUpEvent( this,vMousePosInFormSpace,nButton );

				if( ( m_bBeingDragged == true || m_bBeingResized == true ) && bActionWasUsed == false )
				{
					m_bBeingResized = false;
					m_bBeingDragged = false;
					bActionWasUsed = true;

					this.OnMoved();
				}
				else if( ( m_oForms.DragAndDropInProgress == true || m_oControlMouseDownOn != null )
					&& bActionWasUsed == false && m_bEnabled == true )
				{
					if( m_oControlMouseDownOn != null )
					{
						vLocation = new Vector2( m_oControlMouseDownOn.Location.X,m_oControlMouseDownOn.Location.Y );
						vMousePosInControlSpace = vMousePosInFormSpace - vLocation;
						m_oControlMouseDownOn.OnMouseUp( vMousePosInControlSpace,nButton );
						
						//12/18/2004 Chris Hill  A click up event is also a click event
						OnMouseClick( vMousePosInFormSpace,nButton );
					}

					if( m_oForms.DragAndDropInProgress == true )
					{
						//First send a leave message
						//Send a leave message
						if( DSMisc.BottomMostBaseType( m_oForms.CurrentlyDragAndDropOver.GetType() ).FullName == "DarkStrideToolbox.DSForm" )
						{
							((DSForm)m_oForms.CurrentlyDragAndDropOver).OnDragLeave();
						}
						else
						{
							((DSBaseControl)m_oForms.CurrentlyDragAndDropOver).OnDragLeave();
						}

						//If we are over another contrl they are who gets the drag drop message
						if( m_oForms.CurrentlyDragAndDropOver != null )
						{
							//Send a dragdrop
							if( DSMisc.BottomMostBaseType( m_oForms.CurrentlyDragAndDropOver.GetType() ).FullName == "DarkStrideToolbox.DSForm" )
							{
								((DSForm)m_oForms.CurrentlyDragAndDropOver).OnDragDrop();
							}
							else
							{
								((DSBaseControl)m_oForms.CurrentlyDragAndDropOver).OnDragDrop();
							}		
						}
						else
						{
							this.OnDragDrop();
						}
					}

					//No matter what clear the control down on since they just released the mouse
					m_oControlMouseDownOn = null;

					bActionWasUsed = true;
				}
			}
	
			return( bActionWasUsed );
		}
		public override bool OnMouseMove( Vector2 vMousePosInFormSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;
			DSBaseControl oControl = null;
			Vector2 vMousePosInControlSpace;
			Vector2 vLocation;


			//Moved down to only be called if the form doesn't use the action
			//base.OnMouseMove( vMousePosInFormSpace,baButtons );

			if( m_bVisible == true )
			{
				if( m_oControlMouseDownOn != null )
				{
					vLocation = new Vector2( m_oControlMouseDownOn.Location.X,m_oControlMouseDownOn.Location.Y );
					vMousePosInControlSpace = vMousePosInFormSpace - vLocation;

					m_oControlMouseDownOn.OnMouseMove( vMousePosInControlSpace,baButtons );
					bActionWasUsed = true;
				}
				else
				{
					RaiseMouseMoveEvent( this,vMousePosInFormSpace,baButtons );

					//05/13/2005 Chris Hill  If they are resizing set the new size.
					if( m_bBeingResized == true && bActionWasUsed == false )
					{
						this.Size = vMousePosInFormSpace + m_vFormDraggingToLowerRightDiff;
						this.OnResize();
						bActionWasUsed = true;
					}
					else if( m_bBeingDragged == true && bActionWasUsed == false )
					{
						this.Location = new Point( (int)( vMousePosInFormSpace.X - m_vFormDraggingPoint.X + this.Location.X ),
							(int)( vMousePosInFormSpace.Y - m_vFormDraggingPoint.Y + this.Location.Y ) );
						this.OnMoving();
						this.OnResize();
						bActionWasUsed = true;
					}
					else if( bActionWasUsed == false && m_bEnabled == true )
					{
						oControl = GetControlAt( vMousePosInFormSpace );

						//Check to see if what we are dragging over has changed
						if( ( oControl != null && oControl != m_oForms.CurrentlyMovingOver ) || 
							( oControl == null && this != m_oForms.CurrentlyMovingOver ) )
						{
							//Fire the leave event 
							if( m_oForms.CurrentlyMovingOver != null )
							{
								if( DSMisc.BottomMostBaseType( m_oForms.CurrentlyMovingOver.GetType() ).FullName == "DarkStrideToolbox.DSForm" )
								{
									((DSForm)m_oForms.CurrentlyMovingOver).OnMouseLeave( vMousePosInFormSpace,baButtons );
								}
								else
								{
									((DSBaseControl)m_oForms.CurrentlyMovingOver).OnMouseLeave( vMousePosInFormSpace,baButtons );
								}							
							}
							//Ok now fire the enter event
							if( oControl != null )
							{
								if( m_oForms.CurrentlyMovingOver != oControl )
								{
									m_oForms.CurrentlyMovingOver = oControl;
									oControl.OnMouseEnter( vMousePosInFormSpace,baButtons );
								}
							}
							else
							{
								m_oForms.CurrentlyMovingOver = this;
								this.OnMouseEnter( vMousePosInFormSpace,baButtons );
							}
						}

						//Now do dragging
						if( m_oForms.DragAndDropInProgress == true )
						{
							if( m_oForms.CurrentlyDragAndDropOver == this )
							{
								//Send a move message
								this.OnDragOver();
							}
							else 
							{
								//Send a leave message
								if( DSMisc.BottomMostBaseType( m_oForms.CurrentlyDragAndDropOver.GetType() ).FullName == "DarkStrideToolbox.DSForm" )
								{
									((DSForm)m_oForms.CurrentlyDragAndDropOver).OnDragLeave();
								}
								else
								{
									((DSBaseControl)m_oForms.CurrentlyDragAndDropOver).OnDragLeave();
								}
								//Send an enter message
								m_oForms.CurrentlyDragAndDropOver = this;
								this.OnDragEnter();
							}
						}

						//Respond to the mouse move
						if( oControl != null )
						{
							vLocation = new Vector2( oControl.Location.X,oControl.Location.Y );
							vMousePosInControlSpace = vMousePosInFormSpace - vLocation;
							oControl.OnMouseMove( vMousePosInControlSpace,baButtons );
						}

						//Are we over the hot spot?
						if( IsResizeHotSpot( vMousePosInFormSpace ) == true )
						{
							this.DSGraphicsWrapper.TopmostForm.Cursor = Cursors.SizeNWSE;
						}
						else if( this.IsMoveHotSpot( vMousePosInFormSpace ) == true )
						{
							this.DSGraphicsWrapper.TopmostForm.Cursor = Cursors.SizeAll;
						}
						else
						{
							this.DSGraphicsWrapper.TopmostForm.Cursor = Cursors.Default;
						}

						bActionWasUsed = true;
					}
				}
			}

			if( bActionWasUsed == false )
			{
				bActionWasUsed = base.OnMouseMove( vMousePosInFormSpace,baButtons );
			}

		
			return( bActionWasUsed );
		}
		public override bool OnMouseClick( Vector2 vMousePosInFormSpace,long nButton )
		{
			bool bActionWasUsed = false;
			Vector2 vMousePosInControlSpace;
			Vector2 vLocation;
			DSBaseControl oControlUpOn = null;


			if( m_bVisible == true )
			{
				oControlUpOn = GetControlAt( vMousePosInFormSpace );

				RaiseMouseClickEvent( this,vMousePosInFormSpace,nButton );

				if( oControlUpOn != null && bActionWasUsed == false && m_bEnabled == true )
				{
					if( m_oControlMouseDownOn.Name.Equals( oControlUpOn.Name ) == true )
					{
						vLocation = new Vector2( m_oControlMouseDownOn.Location.X,m_oControlMouseDownOn.Location.Y );
						vMousePosInControlSpace = vMousePosInFormSpace - vLocation;
						m_oControlMouseDownOn.OnMouseClick( vMousePosInControlSpace,nButton );
						bActionWasUsed = true;
					}
				}
			}

	
			return( bActionWasUsed );
		}

		public override bool OnMouseEnter( Vector2 vMousePosInFormSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			if( m_bVisible == true )
			{
				RaiseMouseEnterEvent( this,vMousePosInFormSpace,baButtons );
			}
		
			return( bActionWasUsed );
		}
		public override bool OnMouseLeave( Vector2 vMousePosInFormSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			if( m_bVisible == true )
			{
				RaiseMouseLeaveEvent( this,vMousePosInFormSpace,baButtons );
			}
		
			return( bActionWasUsed );
		}

		public override bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;


			if( m_bVisible == true )
			{
				RaiseKeyDownEvent( this,oKey,oState );

				if( m_oControlWithFocus != null && bActionWasUsed == false && m_bEnabled == true )
				{
					m_oControlWithFocus.OnKeyDown( oKey,oState );
					bActionWasUsed = true;
				}
			}

			return( bActionWasUsed );
		}
		public override bool OnKeyUp( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;
			DSBaseControl oControl = null;


			if( m_bVisible == true )
			{
				RaiseKeyUpEvent( this,oKey,oState );

				if( m_oControlWithFocus != null && bActionWasUsed == false )
				{
					bActionWasUsed = m_oControlWithFocus.OnKeyUp( oKey,oState );
				}

				if( bActionWasUsed == false && m_oControls != null && m_bEnabled == true )
				{
					for( int i=0 ; i<m_oControls.Count ; i++ )
					{
						oControl = (DSBaseControl)m_oControls.GetByIndex( i );
						if( oControl != null && oControl.HotKey == oKey )
						{
							oControl.OnHotKey();
							bActionWasUsed = true;
							break;
						}
					}
				}
			}


			return( bActionWasUsed );
		}


		public virtual bool IsResizeHotSpot( Vector2 vMousePosInFormSpace )
		{
			if( ( vMousePosInFormSpace.X >= this.Size.X - 20 && vMousePosInFormSpace.X <= this.Size.X ) &&
				( vMousePosInFormSpace.Y >= this.Size.Y - 20 && vMousePosInFormSpace.Y <= this.Size.Y ) )
			{
				return( true );
			}
			else
			{
				return( false );
			}			
		}
		public virtual bool IsMoveHotSpot( Vector2 vMousePosInFormSpace )
		{
			if( vMousePosInFormSpace.Y <= 20 )
			{
				return( true );
			}
			else
			{
				return( false );
			}
		}


		public virtual void Dispose()
		{
			m_oControls = null;
			m_oControlMouseDownOn = null;
			m_oControlWithFocus = null;
		}


		public override string Serialize()
		{
			string sRetVal = "";
			string sControls = "";
			DSBaseControl oLoopBaseCtrl = null;


			//Now write all the control information
			for( int i=0 ; i<m_oControls.Count ; i++ )
			{
				oLoopBaseCtrl = (DSBaseControl)m_oControls.GetByIndex( i );
				sControls += oLoopBaseCtrl.GetType().Name + m_cCTRLSEP + 
					oLoopBaseCtrl.GetType().Namespace + m_cCTRLSEP +
					oLoopBaseCtrl.Serialize() + m_cCTRLSEP;
			}

			sRetVal = m_cVERSION_20 + m_cFORMSEP + 
				this.Name + m_cFORMSEP + 
				m_vSize.X.ToString() + m_cFORMSEP + 
				m_vSize.Y.ToString() + m_cFORMSEP + 
				this.Location.X.ToString() + m_cFORMSEP + 
				this.Location.Y.ToString() + m_cFORMSEP + 
				this.GobBorderKey + m_cFORMSEP + 
				sControls;

			return( sRetVal );
		}

		public override string DeSerialize( string sRecord )
		{
			string[] saFormParsed = null;
			string[] saAllCtrlsParsed = null;
			object[] oaArguments = null;
			Assembly oControlAssembly = null;
			Type oControlType = null;
			DSBaseControl oControl = null;


			saFormParsed = DSMisc.Split( sRecord,m_cFORMSEP );

			//Confirm that our versions match
			if( saFormParsed[ 0 ] == m_cVERSION || saFormParsed[ 0 ] == m_cVERSION_20 )
			{
				this.Name = saFormParsed[ 1 ];

				m_vSize = new Vector2( 0,0 );
				m_vSize.X = (float)Convert.ToDouble( saFormParsed[ 2 ] );
				m_vSize.Y = (float)Convert.ToDouble( saFormParsed[ 3 ] );

				//For now don't restore the location.  Its causing problems with overriding the
				//users set locations.
				//this.Location = new Point( (int)Convert.ToDouble( saFormParsed[ 4 ] ),
				//						   (int)Convert.ToDouble( saFormParsed[ 5 ] ) );

				if( saFormParsed[ 0 ] == m_cVERSION_20 )
				{
					this.GobBorderKey = saFormParsed[ 6 ];
					saAllCtrlsParsed = DSMisc.Split( saFormParsed[ 7 ],m_cCTRLSEP );
				}
				else
				{
					saAllCtrlsParsed = DSMisc.Split( saFormParsed[ 6 ],m_cCTRLSEP );
				}

				for( int i=0 ; i<saAllCtrlsParsed.Length-1 ; i+=3 )
				{
					//Deserialize the form into a new object... so first create the new object
					oControlAssembly = Assembly.LoadWithPartialName( saAllCtrlsParsed[ i+1 ] );
					oControlType = oControlAssembly.GetType( saAllCtrlsParsed[ i+1 ] + "." + saAllCtrlsParsed[ i ] );
					//Prepare arguments
					oaArguments = new object[ 2 ];
					oaArguments[ 0 ] = m_oForms;
					oaArguments[ 1 ] = this;
					//Make it!
					oControl = (DSBaseControl)Activator.CreateInstance( oControlType,oaArguments );
					//Now deserialize the form
					oControl.DeSerialize( saAllCtrlsParsed[ i+2 ] );
					
					AddControl( oControl );
				}
			}
			else
			{
				throw new System.Exception( "Form was found with version <" + saFormParsed[ 0 ] + "> which is not valid." );
			}

			return( "" );
		}


		//05/07/2005 Chris Hill  These calls mearly redirect the drawing to the graphics object.  They are needed so that
		//the form can add in its location.
		public void RenderTexture2D( string sTextureKey,System.Drawing.Rectangle oTargetRect,int nColor,System.Drawing.Rectangle oSourceRect )
		{
			Rectangle oNewTarget = oTargetRect;
			oNewTarget.Offset( (int)this.Location.X,(int)this.Location.Y );

			this.m_oDSGraphicsWrapper.RenderTexture2D( sTextureKey, oSourceRect, oNewTarget,
				new Vector2(), 0, 0, false, nColor );


		}
		
		public void RenderRect2D( System.Drawing.Rectangle oTargetRect, int nColor )
		{
			Rectangle oNewTarget = oTargetRect;
			oNewTarget.Offset( (int)this.Location.X,(int)this.Location.Y );

			this.m_oDSGraphicsWrapper.RenderRect2D( oNewTarget,nColor );		
		}


		public void RenderText( System.Drawing.Font oFont,double nX,double nY,Color cColor,string sText )
		{
			this.m_oDSGraphicsWrapper.RenderText( oFont,nX + this.Location.X,nY + this.Location.Y,cColor,sText );
		}

		public void RenderText( System.Drawing.Font oFont,string text, double nX,double nY,double nWidth,double nHeight, bool shadow,BlendColor oFontColor,DrawTextFormat m_oTextFormat )
		{
			this.m_oDSGraphicsWrapper.RenderText( oFont,text, nX+ this.Location.X,nY+ this.Location.Y,nWidth,nHeight, shadow,oFontColor,m_oTextFormat );
		}
		public void RenderText( System.Drawing.Font oFont,string text, System.Drawing.Rectangle rect,BlendColor oFontColor,DrawTextFormat m_oTextFormat) 
		{
			Rectangle oNewTarget = rect;
			oNewTarget.Offset( (int)this.Location.X,(int)this.Location.Y );

			this.m_oDSGraphicsWrapper.RenderText( oFont,text, oNewTarget,oFontColor,m_oTextFormat);
		}
		public void RenderText( System.Drawing.Font oFont,string text, System.Drawing.Rectangle rect, bool shadow,BlendColor oFontColor,DrawTextFormat m_oTextFormat )
		{
			Rectangle oNewTarget = rect;
			oNewTarget.Offset( (int)this.Location.X,(int)this.Location.Y );

			this.m_oDSGraphicsWrapper.RenderText( oFont,text, oNewTarget, shadow,oFontColor,m_oTextFormat );
		}



		public void RenderBorder()
		{
			//this.m_oDSGraphicsWrapper.
		}



		#region Properties
		public string TextureKey
		{
			get
			{
				return( m_sTextureKey );
			}
			set
			{
				m_sTextureKey = value;
			}
		}
		public bool IsModal
		{
			get
			{
				return( m_bIsModal );
			}
			set
			{
				m_bIsModal = value;
				if( value == true )
				{
					m_oForms.MoveFormToTop( this.Name );
				}
			}
		}
		public bool CanBeDragged
		{
			get
			{
				return( m_bCanBeDragged );
			}
			set
			{
				m_bCanBeDragged = value;
			}
		}
		public DSBaseControl ControlWithFocus
		{
			get
			{
				return( m_oControlWithFocus );
			}
		}
		public override DSGraphicsWrapper DSGraphicsWrapper
		{
			get
			{
				return( m_oDSGraphicsWrapper );
			}
			set
			{
				m_oDSGraphicsWrapper = value;

				for( int i=0 ; i<m_oControls.Count ; i++ )
				{
					((DSBaseControl)m_oControls.GetByIndex( i )).DSGraphicsWrapper = value;
				}
			}
		}
		public SortedList Controls
		{
			get
			{
				return( m_oControls );
			}
			set
			{
				m_oControls = value;
			}
		}
		public string Text
		{
			get
			{
				return( m_sText );
			}
			set
			{
				m_sText = value;
			}
		}
		public System.Windows.Forms.FormStartPosition FormStartPosition
		{
			get
			{
				return( m_nFormStartPosition );
			}
			set
			{
				m_nFormStartPosition = value;
			}
		}
		public override Vector2 Size
		{
			get
			{
				return( m_vSize );
			}
			set
			{
				m_vPreResizeSize = m_vSize;
				m_vSize = value;

				if( m_bInOnResize == false )
				{
					m_bInOnResize = true;
					OnResize();
					m_bInOnResize = false;
				}

				m_vPreResizeSize = Vector2.Empty;
			}
		}
		public Vector2 PreResizeSize
		{
			get
			{
				return( m_vPreResizeSize );
			}
		}
		public override System.Drawing.Point Location
		{
			get
			{
				System.Drawing.Point oPos = new System.Drawing.Point( (int)m_vPos.X,(int)m_vPos.Y );
				return( oPos );
			}
			set
			{
				m_bUserSetLocation = true;
				m_vPos.X = value.X;
				m_vPos.Y = value.Y;
				//This is neccessary to force it to recalculate the shape
				this.Size = this.Size;
			}
		}
		public override int Top
		{
			set
			{
				m_bUserSetLocation = true;
				m_vPos.Y = value;
				//This is neccessary to force it to recalculate the shape
				this.Size = this.Size;
			}
		}
		public override int Left
		{
			set
			{
				m_bUserSetLocation = true;
				m_vPos.X = value;
				//This is neccessary to force it to recalculate the shape
				this.Size = this.Size;
			}
		}

		#endregion
	};
	#endregion

	#region Control Classes
	public enum ControlState
	{
		Normal,
		Disabled,
		Hidden,
		Focus,
		MouseOver,
		Pressed,
		LastState // Should always be last
	}

	public struct BlendColor
	{
		public ColorValue[] States; // Modulate colors for all possible control states
		public ColorValue Current; // Current color

		public void Initialize(ColorValue defaultColor, ColorValue disabledColor, ColorValue hiddenColor)
		{
			// Create the array
			States = new ColorValue[(int)ControlState.LastState];
			for(int i = 0; i < States.Length; i++)
			{
				States[i] = defaultColor;
			}

			// Store the data
			States[(int)ControlState.Disabled] = disabledColor;
			States[(int)ControlState.Hidden] = hiddenColor;
			Current = hiddenColor;
		}
		public void Initialize(ColorValue defaultColor) { Initialize( defaultColor, new ColorValue(0.5f, 0.5f, 0.5f, 0.75f),new ColorValue()); }

		public void Blend(ControlState oState, double dElapsedTime, float rate)
		{
			if ((States == null) || (States.Length == 0) )
				return; // Nothing to do

			ColorValue destColor = States[(int)oState];
			Current = ColorOperator.Lerp(Current, destColor, 1.0f - (float)Math.Pow(rate, 30 * dElapsedTime) );
		}
		public void Blend(ControlState oState, double dElapsedTime) { Blend(oState, dElapsedTime, 0.7f); }
	}



	//The goal is to have all these controls exactly mirror the normal .NET controls so that if you know
	//how to use those you can use these.  Unfortunitly I didn't write (steal) them like this.  So they
	//are being converted.. slowly.  Base and Label are up here because they are the only ones i've started.
	#region Base Control
	public abstract class DSBaseControl
	{
		#region Properties
		protected static string m_cFORMTEXTUREKEY = "System_FormAndControlGraphics";
		protected static string m_cSEP = "[CSep;]";
		//02/20/2006 Chris Hill  As I add new properties onto the controls I need to be able
		//to know how to load it in.
		protected static string m_cVERSION_20 = "CtrlVrsn2.0";
		protected static string m_cVERSION_30 = "CtrlVrsn3.0";
		protected static string m_cVERSION_31 = "CtrlVrsn3.1";
		protected static string m_cVERSION_32 = "CtrlVrsn3.2";

		protected double m_dElapsedTime = 0;
		protected double m_dAppTime = 0;
		protected bool m_bIsMouseOver = false;
		protected DSForms m_oForms = null;
		protected DSForm m_oForm = null;

		protected Vector2 m_vSize = new Vector2( 0,0 );
		protected Vector2 m_vPos = new Vector2( 0,0 );
		private string m_sName = "";
		private string m_sMouseCursorTextureKey = "";
		private System.Drawing.Color m_oFontColor = System.Drawing.Color.Black;
		private System.Drawing.Font m_oFont = null;
		protected DSGraphicsWrapper m_oDSGraphicsWrapper = null;

		protected Microsoft.DirectX.DirectInput.Key m_oHotKey;
		protected bool m_bVisible = true;
		protected object m_oUserData = null;
		protected bool m_bEnabled = true;

		protected System.Windows.Forms.AnchorStyles m_nAnchorStyle = ( AnchorStyles.Left | AnchorStyles.Top );

		protected string m_sGobBorderKey = "";

		//Mouse hover event
		private Vector2 m_vMouseHoverLocationInControlSpace = Vector2.Empty;
		private double m_nTimeMouseHasHovered = 0;
		private double m_nTimeMouseHasToHover = 1;
		private bool m_bMouseHoverEventFired = false;
		#endregion

		#region Event code
		public event EventHandler MouseWheelMove;
		public event EventHandler MouseDown;
		public event EventHandler MouseUp;
		public event EventHandler MouseClick;
		public event EventHandler MouseMove;
		public event EventHandler MouseEnter;
		public event EventHandler MouseHover;
		public event EventHandler MouseLeave;
		public event EventHandler KeyUp;
		public event EventHandler KeyDown;
		public event EventHandler DragDrop;
		public event EventHandler DragOver;
		public event EventHandler DragEnter;
		public event EventHandler DragLeave;
		//02/25/2006 Chris Hill  Turns out sometimes you need to render things differently.
		public event EventHandler RenderEvent;
		protected void RaiseMouseWheelMoveEvent(DSBaseControl oSender,long nDirection)
		{
			DSMouseWheelMoveEventArgs oArgs = null;

			if( MouseWheelMove != null )
			{
				oArgs = new DSMouseWheelMoveEventArgs( nDirection );
				MouseWheelMove( oSender, oArgs );
			}
		}
		protected void RaiseMouseDownEvent(DSBaseControl oSender,Vector2 vMousePosInControlSpace,long nButton)
		{
			DSMouseClickEventArgs oArgs = null;

			if( MouseDown != null )
			{
				oArgs = new DSMouseClickEventArgs( vMousePosInControlSpace,nButton );
				MouseDown( oSender, oArgs );
			}
		}		
		protected void RaiseMouseUpEvent(DSBaseControl oSender,Vector2 vMousePosInControlSpace,long nButton)
		{
			DSMouseClickEventArgs oArgs = null;

			if( MouseUp != null )
			{
				oArgs = new DSMouseClickEventArgs( vMousePosInControlSpace,nButton );
				MouseUp( oSender, oArgs );
			}
		}		
		protected void RaiseMouseClickEvent(DSBaseControl oSender,Vector2 vMousePosInControlSpace,long nButton)
		{
			DSMouseClickEventArgs oArgs = null;

			if( MouseClick != null )
			{
				oArgs = new DSMouseClickEventArgs( vMousePosInControlSpace,nButton );
				MouseClick( oSender, oArgs );
			}
		}		
		protected void RaiseMouseMoveEvent(DSBaseControl oSender,Vector2 vMousePosInControlSpace,bool[] baButtons)
		{
			DSMouseMoveEventArgs oArgs = null;

			if( MouseMove != null )
			{
				oArgs = new DSMouseMoveEventArgs( vMousePosInControlSpace,baButtons );
				MouseMove( oSender, oArgs );
			}
		}		
		protected void RaiseKeyUpEvent(DSBaseControl oSender,Microsoft.DirectX.DirectInput.Key oKey,bool[] oState)
		{
			DSKeyEventArgs oArgs = null;

			if( KeyUp != null )
			{
				oArgs = new DSKeyEventArgs( oKey,oState );
				KeyUp( oSender, oArgs );
			}
		}		
		protected void RaiseKeyDownEvent(DSBaseControl oSender,Microsoft.DirectX.DirectInput.Key oKey,bool[] oState)
		{
			DSKeyEventArgs oArgs = null;

			if( KeyDown != null )
			{
				oArgs = new DSKeyEventArgs( oKey,oState );
				KeyDown( oSender, oArgs );
			}
		}		
		protected void RaiseMouseEnterEvent(DSBaseControl oSender,Vector2 vMousePosInControlSpace,bool[] baButtons)
		{
			DSMouseMoveEventArgs oArgs = null;

			if( MouseEnter != null )
			{
				oArgs = new DSMouseMoveEventArgs( vMousePosInControlSpace,baButtons );
				MouseEnter( oSender, oArgs );
			}
		}		
		protected void RaiseMouseHoverEvent(DSBaseControl oSender,Vector2 vMousePosInControlSpace)
		{
			DSMouseMoveEventArgs oArgs = null;

			if( MouseHover != null )
			{
				oArgs = new DSMouseMoveEventArgs( vMousePosInControlSpace,null );
				MouseHover( oSender, oArgs );
			}
		}		
		protected void RaiseMouseLeaveEvent(DSBaseControl oSender,Vector2 vMousePosInControlSpace,bool[] baButtons)
		{
			DSMouseMoveEventArgs oArgs = null;

			if( MouseLeave != null )
			{
				oArgs = new DSMouseMoveEventArgs( vMousePosInControlSpace,baButtons );
				MouseLeave( oSender, oArgs );
			}
		}		
		protected void RaiseDragDropEvent(DSBaseControl oSender)
		{
			DSDragEventArgs oArgs = null;

			if( DragDrop != null )
			{
				oArgs = new DSDragEventArgs( oSender,m_oForms );
				DragDrop( oSender, oArgs );
			}
		}		
		protected void RaiseDragOverEvent(DSBaseControl oSender)
		{
			DSDragEventArgs oArgs = null;

			if( DragOver != null )
			{
				oArgs = new DSDragEventArgs( oSender,m_oForms );
				DragOver( oSender, oArgs );
			}
		}		
		protected void RaiseDragEnterEvent(DSBaseControl oSender)
		{
			DSDragEventArgs oArgs = null;

			if( DragEnter != null )
			{
				oArgs = new DSDragEventArgs( oSender,m_oForms );
				DragEnter( oSender, oArgs );
			}
		}		
		protected void RaiseDragLeaveEvent(DSBaseControl oSender)
		{
			DSDragEventArgs oArgs = null;

			if( DragLeave != null )
			{
				oArgs = new DSDragEventArgs( oSender,m_oForms );
				DragLeave( oSender, oArgs );
			}
		}		
		//02/25/2006 Chris Hill  Turns out sometimes you need to render things differently.
		protected void RaiseRenderEvent(DSBaseControl oSender)
		{
			EventArgs oArgs = null;

			if( RenderEvent != null )
			{
				oArgs = new EventArgs();
				RenderEvent( oSender, oArgs );
			}
		}		
		#endregion


		public DSBaseControl()
		{
		}
		public DSBaseControl( DSForms oForms,DSForm oForm )
		{
			m_oForms = oForms;
			m_oForm = oForm;
		}


		public virtual void Render()
		{
			DSGobTable oGobTable = null;
			System.Drawing.Rectangle oTrgRect = System.Drawing.Rectangle.Empty;


			//If we have a border key then draw that first
			if( m_sGobBorderKey.Length > 0 )
			{
				oGobTable = DSResourceManager.GetGlobalInstance().GetGobTable( m_sGobBorderKey );

				//Did we find our border?
				if( oGobTable != null )
				{
					oTrgRect = new System.Drawing.Rectangle( 
						(int)( oGobTable.BorderFillDiffPoint_Left ), 
						(int)( oGobTable.BorderFillDiffPoint_Top ),
						(int)( this.Size.X - oGobTable.BorderFillDiffPoint_Left - oGobTable.BorderFillDiffPoint_Right ),
						(int)( this.Size.Y - oGobTable.BorderFillDiffPoint_Top - oGobTable.BorderFillDiffPoint_Bottom ) );

					//Start by rendering our background
					if( oGobTable.BorderFillType == enumBorderFillType.Graphic )
					{
						m_oForm.RenderTexture2D( oGobTable.BorderFillGraphicKey,oTrgRect,oGobTable.BorderFillColor,System.Drawing.Rectangle.Empty );
					}
					else if( oGobTable.BorderFillType == enumBorderFillType.Color )
					{
						m_oForm.RenderRect2D( oTrgRect,oGobTable.BorderFillColor );
					}

					//Now render the border itself
					DrawBorder( oGobTable.BorderGraphicKey[ 0 ],oGobTable.BorderGraphicKey[ 1 ],oGobTable.BorderGraphicKey[ 2 ],
						oGobTable.BorderGraphicKey[ 3 ],oGobTable.BorderGraphicKey[ 4 ],
						oGobTable.BorderGraphicKey[ 5 ],oGobTable.BorderGraphicKey[ 6 ],oGobTable.BorderGraphicKey[ 7 ] );
				}
					//If not throw an error
				else
				{
					throw new System.Exception( "Unable to find border <" + m_sGobBorderKey + "> in the Gob files loaded." );
				}
			}

			RaiseRenderEvent( this );
		}

		//02/13/2006 Chris Hill  This function makes drawing a form background easy.
		public void DrawBorder( string sGraphicKey_UpperLeft,string sGraphicKey_UpperMiddle, string sGraphicKey_UpperRight,
			string sGraphicKey_MiddleLeft,string sGraphicKey_MiddleRight,
			string sGraphicKey_LowerLeft,string sGraphicKey_LowerMiddle, string sGraphicKey_LowerRight )
		{
			System.Drawing.Rectangle oWindowsPos = new Rectangle( this.Location.X,this.Location.Y,
				(int)this.Size.X,(int)this.Size.Y );
			this.DSGraphicsWrapper.RenderBorder( oWindowsPos,
				sGraphicKey_UpperLeft,sGraphicKey_UpperMiddle,sGraphicKey_UpperRight,
				sGraphicKey_MiddleLeft,sGraphicKey_MiddleRight,
				sGraphicKey_LowerLeft,sGraphicKey_LowerMiddle,sGraphicKey_LowerRight );
		}

		public virtual string GetCurrentCursorTextureKey( Vector2 vMousePosInControlSpace )
		{
			return( m_sMouseCursorTextureKey );
		}

		public virtual void FrameMove( double dElapsedTime,double dAppTime )
		{
			DSBaseControl oControl = null;


			Vector2 vMouseInControlSpace = new Vector2( m_oForms.DSInputWrapper.MouseCursor.X - this.Location.X,
				m_oForms.DSInputWrapper.MouseCursor.Y - this.Location.Y );


			m_dElapsedTime = dElapsedTime;
			m_dAppTime = dAppTime;


			//Do mouse hovering
			if( this.Visible == false ||
				this.ContainsPoint( new Point( (int)m_oForms.DSInputWrapper.MouseCursor.X,(int)m_oForms.DSInputWrapper.MouseCursor.Y ) ) == false ||
				((Vector2)( vMouseInControlSpace - m_vMouseHoverLocationInControlSpace )).Length() > 10 )
			{
				m_nTimeMouseHasHovered = 0;
				m_vMouseHoverLocationInControlSpace = vMouseInControlSpace;
				m_bMouseHoverEventFired = false;
			}
			else
			{
				oControl = m_oForms.GetFormAt( m_oForms.DSInputWrapper.MouseCursor );
				//Check for a mouse hover event
				m_nTimeMouseHasHovered += dElapsedTime;
				if( m_nTimeMouseHasHovered > m_nTimeMouseHasToHover && m_bMouseHoverEventFired == false 
					&& oControl == this )
				{
					m_bMouseHoverEventFired = true;
					OnMouseHover( m_vMouseHoverLocationInControlSpace );
				}
			}
		}

		public virtual void SetFocus()
		{
			m_oForm.SetFocus( this );
		}


		//06/28/2005 Chris Hill  Adding drag-and-drop capability.
		public virtual void DoDragDrop( object oData )
		{
			m_oForms.DragAndDropInProgress = true;
			m_oForms.DragAndDropData = oData;
			m_oForms.CurrentlyDragAndDropOver = this;
			m_oForms.DragAndDropSourceControl = this;


		}
		public virtual void OnDragOver()
		{
			RaiseDragOverEvent( this );
		}
		public virtual void OnDragLeave()
		{
			RaiseDragLeaveEvent( this );
		}
		public virtual void OnDragEnter()
		{
			RaiseDragEnterEvent( this );
		}
		public virtual void OnDragDrop()
		{
			RaiseDragDropEvent( this );
			m_oForms.DragAndDropInProgress = false;
		}


		//Mouse functions to be overwritten by the user
		public virtual bool OnMouseWheelMove( long nDirection )
		{
			bool bActionWasUsed = false;

			RaiseMouseWheelMoveEvent( this,nDirection );
			
			return( bActionWasUsed );
		}
		public virtual bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			RaiseMouseDownEvent( this,vMousePosInControlSpace,nButton );
			
			return( bActionWasUsed );
		}
		public virtual bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			RaiseMouseUpEvent( this,vMousePosInControlSpace,nButton );

			if( m_oForms.DragAndDropInProgress == true && bActionWasUsed == false && m_bEnabled == true )
			{
				//If we are over another contrl they are who gets the drag drop message
				if( m_oForms.CurrentlyDragAndDropOver != null )
				{
					//Send a leave message
					if( DSMisc.BottomMostBaseType( m_oForms.CurrentlyDragAndDropOver.GetType() ).FullName == "DarkStrideToolbox.DSForm" )
					{
						((DSForm)m_oForms.CurrentlyDragAndDropOver).OnDragDrop();
					}
					else
					{
						((DSBaseControl)m_oForms.CurrentlyDragAndDropOver).OnDragDrop();
					}		
				}
				else
				{
					this.OnDragDrop();
				}
			}

			return( bActionWasUsed );
		}
		public virtual bool OnMouseClick( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			RaiseMouseClickEvent( this,vMousePosInControlSpace,nButton );

			return( bActionWasUsed );
		}
		public virtual bool OnMouseMove( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			RaiseMouseMoveEvent( this,vMousePosInControlSpace,baButtons );

			if( bActionWasUsed == false )
			{
				//Check to see if what we are dragging over has changed
				if( m_oForms.CurrentlyMovingOver != this )
				{
					//Leave the previous control
					if( m_oForms.CurrentlyMovingOver != null )
					{
						if( DSMisc.BottomMostBaseType( m_oForms.CurrentlyMovingOver.GetType() ).FullName == "DarkStrideToolbox.DSForm" )
						{
							((DSForm)m_oForms.CurrentlyMovingOver).OnMouseLeave( vMousePosInControlSpace,baButtons );
						}
						else
						{
							((DSBaseControl)m_oForms.CurrentlyMovingOver).OnMouseLeave( vMousePosInControlSpace,baButtons );
						}	
					}

					//Move onto this control
					this.OnMouseEnter( vMousePosInControlSpace,baButtons );
					m_oForms.CurrentlyMovingOver = this;
				}

				if( m_oForms.DragAndDropInProgress == true )
				{
					if( m_oForms.CurrentlyDragAndDropOver == this )
					{
						//Send a move message
						this.OnDragOver();
					}
					else 
					{
						//Send a leave message
						if( DSMisc.BottomMostBaseType( m_oForms.CurrentlyDragAndDropOver.GetType() ).FullName == "DarkStrideToolbox.DSForm" )
						{
							((DSForm)m_oForms.CurrentlyDragAndDropOver).OnDragLeave();
						}
						else
						{
							((DSBaseControl)m_oForms.CurrentlyDragAndDropOver).OnDragLeave();
						}		
						//Send an enter message
						m_oForms.CurrentlyDragAndDropOver = this;
						this.OnDragEnter();					
					}
				}
					
			}
			
			return( bActionWasUsed );
		}

		public virtual bool OnMouseEnter( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			m_bIsMouseOver = true;
			RaiseMouseEnterEvent( this,vMousePosInControlSpace,baButtons );
			
			return( bActionWasUsed );
		}
		public virtual bool OnMouseHover( Vector2 vMousePosInControlSpace )
		{
			bool bActionWasUsed = false;

			RaiseMouseHoverEvent( this,vMousePosInControlSpace );

			return( bActionWasUsed );
		}
		public virtual bool OnMouseLeave( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			m_bIsMouseOver = false;
			RaiseMouseLeaveEvent( this,vMousePosInControlSpace,baButtons );
			
			return( bActionWasUsed );
		}
		public virtual bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			RaiseKeyDownEvent( this,oKey,oState );
		
			return( bActionWasUsed );
		}

		public virtual bool OnKeyUp( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			RaiseKeyUpEvent( this,oKey,oState );

			return( bActionWasUsed );
		}


		public virtual string Serialize()
		{
			string sRetVal = "";

			sRetVal = m_cVERSION_32 + m_cSEP + 
				m_sName + m_cSEP + 
				m_vSize.X.ToString() + m_cSEP + 
				m_vSize.Y.ToString() + m_cSEP + 
				m_vPos.X.ToString() + m_cSEP + 
				m_vPos.Y.ToString() + m_cSEP + 
				this.Visible.ToString() + m_cSEP + 
				this.Enabled.ToString() + m_cSEP + 
				Convert.ToInt64( m_nAnchorStyle ).ToString() + m_cSEP +
				m_sGobBorderKey + m_cSEP + 
				m_nTimeMouseHasToHover.ToString() + m_cSEP + 
				m_oFontColor.ToArgb().ToString() + m_cSEP;
			
			if( m_oFont == null )
			{
				sRetVal += "" + m_cSEP + 
					"" + m_cSEP + 
					"";
			}
			else
			{
				sRetVal += m_oFont.Name + m_cSEP + 
					m_oFont.Size.ToString() + m_cSEP + 
					Convert.ToInt32( m_oFont.Style ).ToString();						   
			}					

			return( sRetVal );
		}
		public virtual string DeSerialize( string sRecord )
		{
			string[] saParsed = null;
			string sRemainder = "";
			long nStartIndex = 0;
			int nRemainder = 7;


			saParsed = DSMisc.Split( sRecord,m_cSEP );


			//If this version one then we start on index 0.
			if( saParsed[ 0 ] == m_cVERSION_20 )
			{
				nStartIndex = 1;
				nRemainder = 9;
			}
			else if( saParsed[ 0 ] == m_cVERSION_30 )
			{
				nStartIndex = 1;
				nRemainder = 10;
			}
			else if( saParsed[ 0 ] == m_cVERSION_31 )
			{
				nStartIndex = 1;
				nRemainder = 11;
			}
			else if( saParsed[ 0 ] == m_cVERSION_32 )
			{
				nStartIndex = 1;
				nRemainder = 15;
			}

			m_sName = saParsed[ 0+nStartIndex ];

			m_vSize = new Vector2( 0,0 );
			m_vSize.X = (float)Convert.ToDouble( saParsed[ 1+nStartIndex ] );
			m_vSize.Y = (float)Convert.ToDouble( saParsed[ 2+nStartIndex ] );

			m_vPos = new Vector2( 0,0 );
			m_vPos.X = (float)Convert.ToDouble( saParsed[ 3+nStartIndex ] );
			m_vPos.Y = (float)Convert.ToDouble( saParsed[ 4+nStartIndex ] );

			this.Visible = Convert.ToBoolean( saParsed[ 5+nStartIndex ] );
			this.Enabled = Convert.ToBoolean( saParsed[ 6+nStartIndex ] );

			//Added anchor sytle, but old things may not have it so de-serialize properly
			if( saParsed[ 0 ] == m_cVERSION_20 || saParsed[ 0 ] == m_cVERSION_30 || saParsed[ 0 ] == m_cVERSION_31  || saParsed[ 0 ] == m_cVERSION_32 )
			{
				m_nAnchorStyle = (System.Windows.Forms.AnchorStyles)Convert.ToInt64( saParsed[ 7+nStartIndex ] );
			}
			//Added the border graphic key
			if( saParsed[ 0 ] == m_cVERSION_30 || saParsed[ 0 ] == m_cVERSION_31 || saParsed[ 0 ] == m_cVERSION_32 )
			{
				m_sGobBorderKey = saParsed[ 8+nStartIndex ];
			}
			//Add in the hover time
			if( saParsed[ 0 ] == m_cVERSION_31 || saParsed[ 0 ] == m_cVERSION_32 )
			{
				m_nTimeMouseHasToHover = Convert.ToDouble( saParsed[ 9+nStartIndex ] );
			}
			//Add in the font
			if( saParsed[ 0 ] == m_cVERSION_32 )
			{
				this.FontColor = System.Drawing.Color.FromArgb( Convert.ToInt32( saParsed[ 10+nStartIndex ] ) );
				
				if( saParsed[ 11+nStartIndex ].Length > 0 )
				{
					m_oFont = new System.Drawing.Font( 
						saParsed[ 11+nStartIndex ],
						(float)Convert.ToDouble( saParsed[ 12+nStartIndex ] ),
						(System.Drawing.FontStyle)Convert.ToInt32( saParsed[ 13+nStartIndex ] ) );
				}
				else
				{
					m_oFont = null;
				}
			}

			OnResize();

			for( int i=nRemainder ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}

		public virtual DSBaseControl Copy()
		{
			string sControl = "";
			object[] oaArguments = null;
			Assembly oAssembly = null;
			Type oType = null;
			Type oOriginalType = null;
			DSBaseControl oNewControl = null;


			//Deserialize the form into a new object... so first create the new object
			oOriginalType = this.GetType();
			oAssembly = Assembly.LoadWithPartialName( oOriginalType.Namespace );
			oType = oAssembly.GetType( oOriginalType.FullName );
			//Prepare arguments
			oaArguments = new object[ 2 ];
			oaArguments[ 0 ] = this.Forms;
			oaArguments[ 1 ] = this.Form;
			//Make it!
			oNewControl = (DSBaseControl)Activator.CreateInstance( oType,oaArguments );
			//Now deserialize the form
			sControl = this.Serialize();
			oNewControl.DeSerialize( sControl );


			return( oNewControl );
		}


		//Events
		public virtual void OnInitialize() {} // Nothing to do here
		
		public virtual void OnResize(){}					  
		public virtual bool CanHaveFocus { get { return false; } }
		public virtual void OnFocusIn(){}
		public virtual void OnFocusOut(){}
		public virtual void OnHotKey() {} // Nothing to do here
		public virtual bool ContainsPoint(System.Drawing.Point oPointInFormSpace ) 
		{ 
			if( oPointInFormSpace.X >= m_vPos.X && oPointInFormSpace.Y >= m_vPos.Y &&
				oPointInFormSpace.X <= m_vPos.X + m_vSize.X &&
				oPointInFormSpace.Y <= m_vPos.Y + m_vSize.Y )
			{
				return( true ); 
			}
			else
			{
				return( false ); 
			}			
		}
		public virtual bool Enabled { get { return m_bEnabled; } set { m_bEnabled = value; } }
		public virtual bool Visible { get { return m_bVisible; } set { m_bVisible = value; } }



		#region Properties
		public virtual int Top
		{
			get
			{
				return( (int)m_vPos.Y );
			}
			set
			{
				m_vPos.Y = value;
			}
		}
		public virtual int Left
		{
			get
			{
				return( (int)m_vPos.X );
			}
			set
			{
				m_vPos.X = value;
			}
		}
		public virtual int Right
		{
			get
			{
				return( (int)(m_vPos.X + m_vSize.X) );
			}
		}
		public virtual int Bottom
		{
			get
			{
				return( (int)(m_vPos.Y + m_vSize.Y) );
			}
		}
		public virtual System.Drawing.Point Location
		{
			get
			{
				System.Drawing.Point oPos = new System.Drawing.Point( (int)m_vPos.X,(int)m_vPos.Y );
				return( oPos );
			}
			set
			{
				m_vPos.X = value.X;
				m_vPos.Y = value.Y;
				OnResize();
			}
		}
		public virtual Vector2 Size
		{
			get
			{
				return( m_vSize );
			}
			set
			{
				m_vSize = value;
				OnResize();
			}
		}
		private Vector2 Pos
		{
			get
			{
				return( m_vPos );
			}
			set
			{
				m_vPos = value;
				OnResize();
			}
		}

		public virtual string Name
		{
			get
			{
				return( m_sName );
			}
			set
			{
				m_sName = value;
			}
		}
		public virtual string MouseCursorTextureKey
		{
			get
			{
				return( m_sMouseCursorTextureKey );
			}
			set
			{
				m_sMouseCursorTextureKey = value;
			}
		}
		public virtual System.Drawing.Color FontColor
		{
			get
			{
				return( m_oFontColor );
			}
			set
			{
				m_oFontColor = value;
			}
		}
		public virtual System.Drawing.Font Font
		{
			get
			{
				return( m_oFont );
			}
			set
			{
				m_oFont = value;
			}
		}
		public virtual DSGraphicsWrapper DSGraphicsWrapper 
		{
			get
			{
				return( m_oDSGraphicsWrapper );
			}
			set
			{
				m_oDSGraphicsWrapper = value;
			}
		}
		public virtual double ElapsedTime
		{
			get
			{
				return( m_dElapsedTime );
			}
		}
		public virtual double AppTime
		{
			get
			{
				return( m_dAppTime );
			}
		}
		public virtual Microsoft.DirectX.DirectInput.Key HotKey 
		{ 
			get 
			{ 
				return m_oHotKey; 
			} 
			set 
			{ 
				m_oHotKey = value; 
			} 
		}
		public virtual object UserData 
		{ 
			get 
			{ 
				return( m_oUserData ); 
			} 
			set 
			{ 
				m_oUserData = value; 
			} 
		}
		public virtual DSForms Forms
		{
			get
			{
				return( m_oForms );
			}
			set
			{
				m_oForms = value;
			}
		}
		public virtual DSForm Form
		{
			get
			{
				return( m_oForm );
			}
			set
			{
				m_oForm = value;
			}
		}
		public virtual System.Windows.Forms.AnchorStyles Anchor
		{
			get
			{
				return( m_nAnchorStyle );
			}
			set
			{
				m_nAnchorStyle = value;
			}
		}
		public virtual string GobBorderKey
		{
			get
			{
				return( m_sGobBorderKey );
			}
			set
			{
				m_sGobBorderKey = value;
			}
		}
		public virtual double TimeMouseHasToHover
		{
			get
			{
				return( m_nTimeMouseHasToHover );
			}
			set
			{
				m_nTimeMouseHasToHover = value;
			}
		}
		#endregion
	};	
	#endregion

	#region Label Control
	public class DSLabel : DSBaseControl
	{		
		#region Properties
		protected BlendColor m_oFontColor;
		protected DrawTextFormat m_oTextFormat = DrawTextFormat.Center | DrawTextFormat.VerticalCenter;
		private string m_sLabel = "";
		#endregion


		public DSLabel( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );

			//Initialize the graphics for displaying the label
			m_oFontColor.Initialize( oFontColor );
				
			m_oFontColor.States[(int)ControlState.Normal] = oFontColor;
			m_oFontColor.States[(int)ControlState.Focus] = oFontColor;

			m_oFontColor.States[(int)ControlState.Disabled] = new ColorValue(0.75f, 0.75f, 0.75f, 0.75f);
		}


		public override void FrameMove( double dElapsedTime, double dAppTime)
		{
			ControlState oState = ControlState.Normal;


			try
			{
				base.FrameMove (dElapsedTime, dAppTime);

				//Find out what display type to advance.
				if( base.Enabled == false )
				{
					oState = ControlState.Disabled;
				}

				// Blend the element colors
				m_oFontColor.Blend( oState,dElapsedTime );
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}
		}

		public override void Render()
		{
			// Render with a shadow
			if( base.Visible == true )
			{
				base.Render();

				m_oForm.RenderText( 
					base.Font,m_sLabel,
					this.Location.X,this.Location.Y,this.Size.X,this.Size.Y,
					true,m_oFontColor,m_oTextFormat );
			}
		}


		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() + m_cSEP + m_sLabel;

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;


			sRecordLeft = base.DeSerialize( sRecord );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			m_sLabel = saParsed[ 0 ];

			for( int i=1 ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}



		#region Properties
		public string Label
		{
			get
			{
				return( m_sLabel );
			}
			set
			{
				m_sLabel = value;
			}
		}
		public override System.Drawing.Color FontColor
		{
			get
			{
				return( base.FontColor );
			}
			set
			{
				base.FontColor = value;
				Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );
				m_oFontColor.States[(int)ControlState.Normal] = oFontColor;
				m_oFontColor.States[(int)ControlState.Focus] = oFontColor;
			}
		}
		#endregion 
	}
	#endregion

	//These need to be converted
	#region Button Control
	public class DSButton : DSLabel
	{
		#region Properties
		protected BlendColor m_oBackLayer_TextureState = new BlendColor();
		protected BlendColor m_oBackLayer_FontColor = new BlendColor();
		protected BlendColor m_oFillLayer_TextureState = new BlendColor();
		protected BlendColor m_oFillLayer_FontColor = new BlendColor();
		protected System.Drawing.Rectangle m_oBackLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected System.Drawing.Rectangle m_oFillLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected new DrawTextFormat m_oTextFormat = DrawTextFormat.Center | DrawTextFormat.VerticalCenter;

		public const int m_cButtonLayer = 0;
		public const int m_cFillLayer = 1;
		protected bool m_bIsPressed = false;

		#region Event code
		public event EventHandler Click;
		protected void RaiseClickEvent(DSButton sender, bool wasTriggeredByUser)
		{
			if (Click != null)
			{
				Click(sender, EventArgs.Empty);
			}
		}
		#endregion
		#endregion


		public DSButton( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );


			m_oBackLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oBackLayer_TextureState.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
			m_oBackLayer_TextureState.States[(int)ControlState.Pressed] = new ColorValue(1.0f, 1.0f, 1.0f, 0.85f);

			m_oBackLayer_TextureRect = new System.Drawing.Rectangle(0,0,136,54);

			m_oBackLayer_FontColor.Initialize( oFontColor );
			m_oBackLayer_FontColor.States[(int)ControlState.MouseOver] = DSForm.BlackColorValue;

			m_oFillLayer_TextureState.Initialize( DSForm.TransparentWhite );
			m_oFillLayer_TextureState.States[(int)ControlState.MouseOver] = new ColorValue(1.0f, 1.0f, 1.0f, 0.6f);
			m_oFillLayer_TextureState.States[(int)ControlState.Pressed] = new ColorValue(0,0,0, 0.25f);
			m_oFillLayer_TextureState.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.05f);

			m_oFillLayer_TextureRect = new System.Drawing.Rectangle(136,0,136,54);

			m_oFillLayer_FontColor.Initialize( oFontColor );
			m_oFillLayer_FontColor.States[(int)ControlState.MouseOver] = DSForm.BlackColorValue;


			//We need to set the various states, like focus.
			m_oBackLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
			m_oFillLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;

			m_oBackLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
			m_oFillLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;

			m_oBackLayer_FontColor.States[(int)ControlState.Pressed] = oFontColor;
			m_oFillLayer_FontColor.States[(int)ControlState.Pressed] = oFontColor;
		}


		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseDown( vMousePosInControlSpace,nButton );

				m_bIsPressed = true;
				bActionWasUsed = true;
			}

			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseUp( vMousePosInControlSpace,nButton );

				if( m_bIsPressed == true )
				{
					m_bIsPressed = false;
					bActionWasUsed = true;
					RaiseClickEvent(this,true);					
				}
			}
		
			return( bActionWasUsed );
		}


		public override bool OnKeyUp( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnKeyUp( oKey,oState );

				if( oKey == Microsoft.DirectX.DirectInput.Key.Space )
				{
					m_bIsPressed = false;
					bActionWasUsed = true;
					RaiseClickEvent(this, true);
				}
			}
		
			return( bActionWasUsed );
		}

		public override bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnKeyDown( oKey,oState );

				if( oKey == Microsoft.DirectX.DirectInput.Key.Space)
				{
					m_bIsPressed = true;
				}
			}

			return( bActionWasUsed );
		}


		public override void Render()
		{
			int nOffsetX = 0;
			int nOffsetY = 0;
			float fBlendRate;
			ControlState oState = ControlState.Normal;


			if( Visible == false )
			{
				oState = ControlState.Hidden;
			}
			else if (Enabled == false)
			{
				oState = ControlState.Disabled;
			}
			else if (m_bIsPressed)
			{
				oState = ControlState.Pressed;
				nOffsetX = 1;
				nOffsetY = 2;
			}
			else if (m_bIsMouseOver)
			{
				oState = ControlState.MouseOver;
				nOffsetX = -1;
				nOffsetY = -2;
			}
			else if ( m_oForm.ControlWithFocus == this )
			{					
				oState = ControlState.Focus;
			}

			// Background fill layer
			fBlendRate = (oState == ControlState.Pressed) ? 0.0f : 0.8f;
        
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			System.Drawing.Rectangle m_oButtonRect = boundingBox;
			m_oButtonRect.Offset(nOffsetX, nOffsetY);

			// Blend current color
			m_oBackLayer_TextureState.Blend(oState, m_dElapsedTime, fBlendRate);
			m_oBackLayer_FontColor.Blend(oState, m_dElapsedTime, fBlendRate);

			// Draw sprite/text of button
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oButtonRect,m_oBackLayer_TextureState.Current.ToArgb(),m_oBackLayer_TextureRect);
			m_oForm.RenderText( base.Font,base.Label,m_oButtonRect,m_oBackLayer_FontColor,m_oTextFormat);

			// Blend current color
			m_oFillLayer_TextureState.Blend(oState, m_dElapsedTime, fBlendRate);
			m_oFillLayer_FontColor.Blend(oState, m_dElapsedTime, fBlendRate);

			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oButtonRect,m_oFillLayer_TextureState.Current.ToArgb(),m_oFillLayer_TextureRect);
			m_oForm.RenderText( base.Font,base.Label,  m_oButtonRect,m_oFillLayer_FontColor,m_oTextFormat);
		}


		public override bool CanHaveFocus { get { return Visible && Enabled; } }
		public override void OnHotKey()
		{
			RaiseClickEvent(this, true);
		}



		#region Properties
		public override System.Drawing.Color FontColor
		{
			get
			{
				return( base.FontColor );
			}
			set
			{
				base.FontColor = value;
				Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );
				m_oBackLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
				m_oFillLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;

				m_oBackLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
				m_oFillLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;

				m_oBackLayer_FontColor.States[(int)ControlState.Pressed] = oFontColor;
				m_oFillLayer_FontColor.States[(int)ControlState.Pressed] = oFontColor;
			}
		}
		#endregion
	}
	#endregion

	#region CheckBox Control
	public class DSCheckBox : DSButton
	{
		#region Properties
		protected BlendColor m_oBoxLayer_TextureState = new BlendColor();
		protected BlendColor m_oBoxLayer_FontColor = new BlendColor();
		protected BlendColor m_oCheckLayer_TextureState = new BlendColor();
		protected System.Drawing.Rectangle m_oBoxLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected System.Drawing.Rectangle m_oCheckLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected new DrawTextFormat m_oTextFormat = DrawTextFormat.Left | DrawTextFormat.VerticalCenter;

		protected System.Drawing.Rectangle m_oButtonRect;
		protected System.Drawing.Rectangle m_oTextRect;

		protected bool m_bBoxIsChecked = false;

		public const int m_cBoxLayer = 0;
		public const int m_cCheckLayer = 1;

		#region Event code
		public event EventHandler Changed;
		/// <summary>Create new button instance</summary>
		protected void RaiseChangedEvent(DSCheckBox sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			// m_bEnabled
			if ( !wasTriggeredByUser)
				return;

			// Fire both the changed and clicked event
			base.RaiseClickEvent(sender, wasTriggeredByUser);
			if (Changed != null)
				Changed(sender, EventArgs.Empty);
		}
		#endregion
		#endregion

		
		public DSCheckBox( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );

			m_bBoxIsChecked = false;

			m_oBoxLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oBoxLayer_TextureState.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
			m_oBoxLayer_TextureState.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.8f);
			m_oBoxLayer_TextureState.States[(int)ControlState.Pressed] = DSForm.WhiteColorValue;
			m_oBoxLayer_TextureRect = new System.Drawing.Rectangle(0,54,27,27);
			m_oBoxLayer_FontColor.Initialize( oFontColor );
			m_oBoxLayer_FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.8f);;

			m_oCheckLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oCheckLayer_TextureRect = new System.Drawing.Rectangle(27,54,27,27);

			
			m_oBoxLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
			m_oBoxLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
		}


		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() + m_cSEP +  
					  m_bBoxIsChecked.ToString() + m_cSEP;

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;


			sRecordLeft = base.DeSerialize( sRecord );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			if( saParsed.Length > 0 && saParsed[ 0 ].Length > 0 )
			{
				m_bBoxIsChecked = Convert.ToBoolean( saParsed[ 0 ] );
			}

			for( int i=1 ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}


		public override bool ContainsPoint(System.Drawing.Point pt)
		{
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			return (boundingBox.Contains(pt) || m_oButtonRect.Contains(pt));
		}

		public override void Render()
		{
			ControlState oState = ControlState.Normal;
			float blendRate = 0.0f;


			if (Visible == false)
			{
				oState = ControlState.Hidden;
			}
			else if (Enabled == false)
			{
				oState = ControlState.Disabled;
			}
			else if (m_bIsPressed)
			{
				oState = ControlState.Pressed;
			}
			else if (m_bIsMouseOver)
			{
				oState = ControlState.MouseOver;
			}
			else if ( m_oForm.ControlWithFocus == this )
			{
				oState = ControlState.Focus;
			}

			if( Visible == true )
			{
				//base.Render();
			}

			blendRate = (oState == ControlState.Pressed) ? 0.0f : 0.8f;
            
			// Blend current color
			m_oBoxLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oBoxLayer_FontColor.Blend(oState, m_dElapsedTime, blendRate);

			// Draw sprite/text of checkbox
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oButtonRect,m_oBoxLayer_TextureState.Current.ToArgb(),m_oBoxLayer_TextureRect );
			m_oForm.RenderText( base.Font,base.Label,  m_oTextRect,m_oBoxLayer_FontColor,m_oTextFormat );

			if (!m_bBoxIsChecked)
			{
				oState = ControlState.Hidden;
			}

			// Blend current color
			m_oCheckLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);

			// Draw sprite of checkbox
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oButtonRect,m_oCheckLayer_TextureState.Current.ToArgb(),m_oCheckLayer_TextureRect );
		}

		public override void OnResize()
		{
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			// Update the two rects
			m_oButtonRect = boundingBox;
			m_oButtonRect = new System.Drawing.Rectangle(boundingBox.Location,
				new System.Drawing.Size(boundingBox.Height, boundingBox.Height));

			m_oTextRect = boundingBox;
			m_oTextRect.Offset((int) (1.25f * m_oButtonRect.Width), 0);
		}

		public override bool OnKeyUp( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if( oKey == Microsoft.DirectX.DirectInput.Key.Space )
				{
					if (m_bIsPressed)
					{
						m_bIsPressed = false;
						bActionWasUsed = true;
						m_bBoxIsChecked = !m_bBoxIsChecked;
						RaiseChangedEvent( this,true );
					}
				}
			}
		
			return( bActionWasUsed );
		}

		public override bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if( oKey == Microsoft.DirectX.DirectInput.Key.Space)
				{
					m_bIsPressed = true;
					bActionWasUsed = true;
				}
			}
		
			return( bActionWasUsed );
		}


		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseDown( vMousePosInControlSpace,nButton );

				m_bIsPressed = true;
				bActionWasUsed = true;
			}
		
			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if (m_bIsPressed)
				{
					m_bIsPressed = false;
					m_bBoxIsChecked = !m_bBoxIsChecked;
					RaiseChangedEvent( this,true );
					bActionWasUsed = true;
				}
			}

			return( bActionWasUsed );
		}


		public override void OnHotKey()
		{
			m_bBoxIsChecked = false;
			RaiseChangedEvent( this,true );
		}



		#region Properties
		public virtual bool IsChecked
		{
			get { return m_bBoxIsChecked; }
			set 
			{ 
				m_bBoxIsChecked = value;
				RaiseChangedEvent( this,false );
			}
		}
		public override System.Drawing.Color FontColor
		{
			get
			{
				return( base.FontColor );
			}
			set
			{
				base.FontColor = value;
				Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );
				m_oBoxLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
				m_oBoxLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
			}
		}
		#endregion
	}
	#endregion

	#region RadioButton Control
	public class DSRadioButton : DSCheckBox
	{
		#region Properties
		protected int m_nButtonGroupIndex;
		#endregion


		public DSRadioButton( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			m_oBoxLayer_TextureRect = new System.Drawing.Rectangle(54,54,27,27);
			m_oCheckLayer_TextureRect = new System.Drawing.Rectangle(81,54,27,27);
		}


		public void SetChecked(bool ischecked, bool clear)
		{
			m_bBoxIsChecked = ischecked;
			RaiseChangedEvent(this, false);
		}

		public override void OnHotKey()
		{
			m_bBoxIsChecked = true;
			RaiseChangedEvent(this, true);
		}

		public void ClearRadioButtonGroup(int groupIndex)
		{
			DSBaseControl oLoopBaseCtrl = null;
			DSRadioButton oRadioButton = new DSRadioButton( null,null );

			// Find all radio buttons with the given group number
			for( int i=0 ; i<m_oForm.Controls.Count ; i++ )
			{
				oLoopBaseCtrl = (DSBaseControl)m_oForm.Controls.GetByIndex( i );
				if( oLoopBaseCtrl.GetType() == oRadioButton.GetType() )
				{
					oRadioButton = (DSRadioButton)oLoopBaseCtrl;
					if( oRadioButton.ButtonGroup == groupIndex )
					{
						oRadioButton.SetChecked( false,false );
					}
				}
			}
		}



		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() + m_cSEP +
					  m_nButtonGroupIndex.ToString();

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;


			sRecordLeft = base.DeSerialize( sRecord );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			m_nButtonGroupIndex = Convert.ToInt32( saParsed[ 0 ] );

			for( int i=1 ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}


		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseDown( vMousePosInControlSpace,nButton );

				// Pressed while inside the control
				m_bIsPressed = true;
				bActionWasUsed = true;
			}
		
			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseUp( vMousePosInControlSpace,nButton );

				if (m_bIsPressed)
				{
					m_bIsPressed = false;
					bActionWasUsed = true;

					ClearRadioButtonGroup( m_nButtonGroupIndex );
					m_bBoxIsChecked = !m_bBoxIsChecked;

					RaiseChangedEvent(this, true);
				}
			}
		
			return( bActionWasUsed );
		}


		public override bool OnKeyUp( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnKeyUp( oKey,oState );

				if( oKey == Microsoft.DirectX.DirectInput.Key.Space )
				{
					m_bIsPressed = false;
					bActionWasUsed = true;
				}
			}
		
			return( bActionWasUsed );
		}

		public override bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnKeyDown( oKey,oState );

				if( oKey == Microsoft.DirectX.DirectInput.Key.Space)
				{
					m_bIsPressed = false;
					bActionWasUsed = true;
					ClearRadioButtonGroup( m_nButtonGroupIndex );
					m_bBoxIsChecked = !m_bBoxIsChecked;

					RaiseChangedEvent(this, true);
				}
			}

			return( bActionWasUsed );
		}



		#region Properties
		public int ButtonGroup
		{
			get { return m_nButtonGroupIndex; }
			set { m_nButtonGroupIndex = value; }
		}
		#endregion
	}

	#endregion

	#region VertScrollBar Control
	public class DSVertScrollBar : DSBaseControl
	{
		#region Properties
		protected BlendColor m_oTrackLayer_TextureState = new BlendColor();
		protected BlendColor m_oUpArrowLayer_TextureState = new BlendColor();
		protected BlendColor m_oDownArrowLayer_TextureState = new BlendColor();
		protected BlendColor m_oThumbLayer_TextureState = new BlendColor();

		protected System.Drawing.Rectangle m_oTrackLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected System.Drawing.Rectangle m_oUpArrowLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected System.Drawing.Rectangle m_oDownArrowLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected System.Drawing.Rectangle m_oThumbLayer_TextureRect; // Bounding rectangle of this element on the composite texture

		public const int m_cTrackLayer = 0;
		public const int m_cUpButtonLayer = 1;
		public const int m_cDownButtonLayer = 2;
		public const int m_cThumbLayer = 3;
		protected const int m_cMinimumThumbSize = 8;

		private int m_nSmallChange = 1;
		private int m_nLargeChange = 10;

		protected bool m_bShowingThumb = true;
		protected System.Drawing.Rectangle m_oUpButtonRect = System.Drawing.Rectangle.Empty;
		protected System.Drawing.Rectangle m_oDownButtonRect = System.Drawing.Rectangle.Empty;
		protected System.Drawing.Rectangle m_oTrackRect = System.Drawing.Rectangle.Empty;
		protected System.Drawing.Rectangle m_oThumbRect = System.Drawing.Rectangle.Empty;
		protected int m_nPosition = 0; // Position of the first displayed item
		protected int m_nPageSize = 1; // How many items are displayable in one page
		protected int m_nStart = 0; // First item
		protected int m_nEnd = 1; // The index after the last item
		private int m_nThumbOffsetY;
		private bool m_bIsDragging;
		#endregion


		public DSVertScrollBar( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			m_oForms = oForms;
			m_oForm = oForm;

			m_oTrackLayer_TextureState.Initialize(DSForm.WhiteColorValue);
			m_oTrackLayer_TextureRect = new System.Drawing.Rectangle(243,144,22,11);

			m_oUpArrowLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oUpArrowLayer_TextureState.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 1.0f);
			m_oUpArrowLayer_TextureRect = new System.Drawing.Rectangle(243,124,22,20);

			m_oDownArrowLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oDownArrowLayer_TextureState.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 1.0f);
			m_oDownArrowLayer_TextureRect = new System.Drawing.Rectangle(243,155,22,21);

			m_oThumbLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oThumbLayer_TextureRect = new System.Drawing.Rectangle(266,123,20,44);
		}


		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() +  m_cSEP +
					  m_bShowingThumb.ToString() + m_cSEP +
					  m_nPosition.ToString() + m_cSEP + 
					  m_nPageSize.ToString() + m_cSEP + 
					  m_nStart.ToString() + m_cSEP + 
					  m_nEnd.ToString() + m_cSEP + 
					  m_nSmallChange.ToString() + m_cSEP + 
					  m_nLargeChange.ToString();

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;
			int i = 5;


			sRecordLeft = base.DeSerialize( sRecord );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			m_bShowingThumb = Convert.ToBoolean( saParsed[ 0 ] );
			m_nPosition = Convert.ToInt32( saParsed[ 1 ] );
			m_nPageSize = Convert.ToInt32( saParsed[ 2 ] );
			m_nStart = Convert.ToInt32( saParsed[ 3 ] );
			m_nEnd = Convert.ToInt32( saParsed[ 4 ] );

			if( saParsed.Length > 13 )
			{
				m_nSmallChange = Convert.ToInt32( saParsed[ 5 ] );
				m_nLargeChange = Convert.ToInt32( saParsed[ 6 ] );
				i = 7;
			}

			for( ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}


		public override void Render()
		{
			ControlState oState = ControlState.Normal;


			if (Visible == false)
			{
				oState = ControlState.Hidden;
			}
			else if ( (Enabled == false) || (m_bShowingThumb == false) )
			{
				oState = ControlState.Disabled;
			}
			else if (m_bIsMouseOver)
			{
				oState = ControlState.MouseOver;
			}
			else if (m_oForm.ControlWithFocus == this)
			{
				oState = ControlState.Focus;
			}

			if( Visible == true )
			{
				base.Render();
			}


			float blendRate = (oState == ControlState.Pressed) ? 0.0f : 0.8f;

			// Track 
			m_oTrackLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oTrackRect,m_oTrackLayer_TextureState.Current.ToArgb(),m_oTrackLayer_TextureRect );

			// Up arrow
			m_oUpArrowLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oUpButtonRect,m_oUpArrowLayer_TextureState.Current.ToArgb(),m_oUpArrowLayer_TextureRect );

			// Down arrow
			m_oDownArrowLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oDownButtonRect,m_oDownArrowLayer_TextureState.Current.ToArgb(),m_oDownArrowLayer_TextureRect );

			// Thumb button
			m_oThumbLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oThumbRect,m_oThumbLayer_TextureState.Current.ToArgb(),m_oThumbLayer_TextureRect );
		}


		public override void OnResize()
		{
			// Get the bounding box first
			//base.UpdateRectangles();

			// Make sure buttons are square
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			m_oUpButtonRect = new System.Drawing.Rectangle(boundingBox.Location,
				new System.Drawing.Size(boundingBox.Width, boundingBox.Width));

			m_oDownButtonRect = new System.Drawing.Rectangle(boundingBox.Left, boundingBox.Bottom - boundingBox.Width,
				boundingBox.Width, boundingBox.Width);

			m_oTrackRect = new System.Drawing.Rectangle(m_oUpButtonRect.Left, m_oUpButtonRect.Bottom, 
				m_oUpButtonRect.Width, m_oDownButtonRect.Top - m_oUpButtonRect.Bottom);

			m_oThumbRect = m_oUpButtonRect;

			UpdateThumbRectangle();
		}

		protected void Cap()
		{
			if (m_nPosition < m_nStart || m_nEnd - m_nStart <= m_nPageSize)
			{
				m_nPosition = m_nStart;
			}
			else if (m_nPosition + m_nPageSize > m_nEnd)
				m_nPosition = m_nEnd - m_nPageSize;
		}

		protected void UpdateThumbRectangle()
		{
			if (m_nEnd - m_nStart > m_nPageSize)
			{
				int thumbHeight = Math.Max(m_oTrackRect.Height * m_nPageSize / (m_nEnd-m_nStart), m_cMinimumThumbSize);
				int maxPosition = m_nEnd - m_nStart - m_nPageSize;
				m_oThumbRect.Location = new System.Drawing.Point(m_oThumbRect.Left,
					m_oTrackRect.Top + (m_nPosition - m_nStart) * (m_oTrackRect.Height - thumbHeight) / maxPosition);
				m_oThumbRect.Size = new System.Drawing.Size(m_oThumbRect.Width, thumbHeight);
				m_bShowingThumb = true;
			}
			else
			{
				// No content to scroll
				m_oThumbRect.Height = 0;
				m_bShowingThumb = false;
			}
		}


		public void Scroll(int delta)
		{
			// Perform scroll
			m_nPosition += delta;
			// Cap m_nPosition
			Cap();
			// Update thumb rectangle
			UpdateThumbRectangle();
		}

		public void ShowItem(int index)
		{
			// Cap the index
			if (index < 0)
				index = 0;

			if (index >= m_nEnd)
				index = m_nEnd - 1;

			// Adjust the m_nPosition to show this item
			if (m_nPosition > index)
				m_nPosition = index;
			else if (m_nPosition + m_nPageSize <= index)
				m_nPosition = index - m_nPageSize + 1;

			// Update thumbs again
			UpdateThumbRectangle();
		}

		public void SetTrackRange(int startRange, int endRange)
		{
			m_nStart = startRange; 
			m_nEnd = endRange;
			Cap();
			UpdateThumbRectangle();
		}

		
		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseDown( vMousePosInControlSpace,nButton );

				// Check for on up button
				if (m_oUpButtonRect.Contains((int)(vMousePosInControlSpace.X + this.Location.X),
											 (int)(vMousePosInControlSpace.Y + this.Location.Y) ))
				{
					m_nPosition -= m_nSmallChange;
					m_nPosition = DSMisc.Max( m_nStart,m_nPosition );
					UpdateThumbRectangle();
				}
				// Check for on down button
				else if (m_oDownButtonRect.Contains((int)(vMousePosInControlSpace.X + this.Location.X),
													(int)(vMousePosInControlSpace.Y + this.Location.Y)))
				{
					m_nPosition += m_nSmallChange;
					m_nPosition = DSMisc.Min( m_nEnd - m_nPageSize,m_nPosition );
					UpdateThumbRectangle();
				}
				// Check for click on thumb
				else if (m_oThumbRect.Contains(	(int)(vMousePosInControlSpace.X + this.Location.X),
												(int)(vMousePosInControlSpace.Y + this.Location.Y)))
				{
					m_bIsDragging = true;
					m_nThumbOffsetY = (int)vMousePosInControlSpace.Y - m_oThumbRect.Top;
				}
				// check for click on track
				else if (m_oThumbRect.Left <= vMousePosInControlSpace.X &&
						 m_oThumbRect.Right > vMousePosInControlSpace.X)
				{
					if (m_oThumbRect.Top > vMousePosInControlSpace.Y &&
						m_oTrackRect.Top <= vMousePosInControlSpace.Y)
					{
						Scroll(-(m_nPageSize-1));
					}
					else if (m_oThumbRect.Bottom <= vMousePosInControlSpace.Y &&
							 m_oTrackRect.Bottom > vMousePosInControlSpace.Y)
					{
						Scroll(m_nPageSize-1);
					}
				}
				//They clicked in the track but not on the button
				else if( m_oTrackRect.Contains(	(int)(vMousePosInControlSpace.X + this.Location.X),
												(int)(vMousePosInControlSpace.Y + this.Location.Y) ))
				{
					if( (int)( vMousePosInControlSpace.Y + this.Location.Y ) < m_oThumbRect.Y )
					{
						m_nPosition -= m_nLargeChange;
						m_nPosition = DSMisc.Max( m_nStart,m_nPosition );
					}
					else
					{
						m_nPosition += m_nLargeChange;
						m_nPosition = DSMisc.Min( m_nEnd - m_nPageSize,m_nPosition );
					}
				}

				bActionWasUsed = true;
			}
			
			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseUp( vMousePosInControlSpace,nButton );

				m_bIsDragging = false;
				bActionWasUsed = true;
				UpdateThumbRectangle();
			}

			return( bActionWasUsed );
		}

		public override bool OnMouseMove( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseMove( vMousePosInControlSpace,baButtons );

				if (m_bIsDragging)
				{
					// Calculate new bottom and top of thumb rect
					int bottom = m_oThumbRect.Bottom + ((int)vMousePosInControlSpace.Y - m_nThumbOffsetY - m_oThumbRect.Top);
					int top = (int)vMousePosInControlSpace.Y - m_nThumbOffsetY;
					m_oThumbRect = new System.Drawing.Rectangle(m_oThumbRect.Left, top, m_oThumbRect.Width, bottom - top);
					if (m_oThumbRect.Top < m_oTrackRect.Top)
						m_oThumbRect.Offset(0, m_oTrackRect.Top - m_oThumbRect.Top);
					else if (m_oThumbRect.Bottom > m_oTrackRect.Bottom)
						m_oThumbRect.Offset(0, m_oTrackRect.Bottom - m_oThumbRect.Bottom);

					// Compute first item index based on thumb m_nPosition
					int maxFirstItem = m_nEnd - m_nStart - m_nPageSize; // Largest possible index for first item
					int maxThumb = m_oTrackRect.Height - m_oThumbRect.Height; // Largest possible thumb m_nPosition

					m_nPosition = m_nStart + (m_oThumbRect.Top - m_oTrackRect.Top +
								  maxThumb / (maxFirstItem * 2) ) * // Shift by half a row to avoid last row covered
								  maxFirstItem / maxThumb;

					bActionWasUsed = true;
				}
			}
		
			return( bActionWasUsed );
		}



		#region Properties
		public int StartRange
		{
			get
			{
				return( m_nStart );
			}
		}
		public int EndRange
		{
			get
			{
				return( m_nEnd );
			}
		}
		public int TrackPosition
		{
			get { return m_nPosition; }
			set { m_nPosition = value; Cap(); UpdateThumbRectangle(); }
		}

		public int PageSize
		{
			get { return m_nPageSize; }
			set { m_nPageSize = value; Cap(); UpdateThumbRectangle(); }
		}
		public int SmallChange
		{
			get 
			{ 
				return( m_nSmallChange ); 
			}
			set 
			{ 
				m_nSmallChange = value; 
			}
		}
		public int LargeChange
		{
			get 
			{ 
				return( m_nLargeChange ); 
			}
			set 
			{ 
				m_nLargeChange = value; 
			}
		}
		#endregion
	}
	#endregion

	#region HorzScrollBar Control
	public class DSHorzScrollBar : DSBaseControl
	{
		#region Properties
		protected BlendColor m_oTrackLayer_TextureState = new BlendColor();
		protected BlendColor m_oLeftArrowLayer_TextureState = new BlendColor();
		protected BlendColor m_oRightArrowLayer_TextureState = new BlendColor();
		protected BlendColor m_oThumbLayer_TextureState = new BlendColor();

		protected System.Drawing.Rectangle m_oTrackLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected System.Drawing.Rectangle m_oLeftArrowLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected System.Drawing.Rectangle m_oRightArrowLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected System.Drawing.Rectangle m_oThumbLayer_TextureRect; // Bounding rectangle of this element on the composite texture

		public const int m_cTrackLayer = 0;
		public const int m_cUpButtonLayer = 1;
		public const int m_cDownButtonLayer = 2;
		public const int m_cThumbLayer = 3;
		protected const int m_cMinimumThumbSize = 8;

		private int m_nSmallChange = 1;
		private int m_nLargeChange = 10;

		protected bool m_bShowingThumb = true;
		protected System.Drawing.Rectangle m_oLeftButtonRect = System.Drawing.Rectangle.Empty;
		protected System.Drawing.Rectangle m_oRightButtonRect = System.Drawing.Rectangle.Empty;
		protected System.Drawing.Rectangle m_oTrackRect = System.Drawing.Rectangle.Empty;
		protected System.Drawing.Rectangle m_oThumbRect = System.Drawing.Rectangle.Empty;
		protected int m_nPosition = 0; // Position of the first displayed item
		protected int m_nPageSize = 1; // How many items are displayable in one page
		protected int m_nStart = 0; // First item
		protected int m_nEnd = 1; // The index after the last item
		private int m_nThumbOffsetX;
		private bool m_bIsDragging;
		#endregion


		public DSHorzScrollBar( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			m_oTrackLayer_TextureState.Initialize(DSForm.WhiteColorValue);
			m_oTrackLayer_TextureRect = new System.Drawing.Rectangle(263,178,11,22);

			m_oLeftArrowLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oLeftArrowLayer_TextureState.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 1.0f);
			m_oLeftArrowLayer_TextureRect = new System.Drawing.Rectangle(243,178,21,22);

			m_oRightArrowLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oRightArrowLayer_TextureState.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 1.0f);
			m_oRightArrowLayer_TextureRect = new System.Drawing.Rectangle(275,178,21,22);

			m_oThumbLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oThumbLayer_TextureRect = new System.Drawing.Rectangle(246,210,44,20);
		}


		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() +  m_cSEP +
					  m_bShowingThumb.ToString() + m_cSEP +
					  m_nPosition.ToString() + m_cSEP + 
					  m_nPageSize.ToString() + m_cSEP + 
					  m_nStart.ToString() + m_cSEP + 
					  m_nEnd.ToString() + m_cSEP + 
					  m_nSmallChange.ToString() + m_cSEP + 
					  m_nLargeChange.ToString();

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;
			int i = 5;


			sRecordLeft = base.DeSerialize( sRecord );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			m_bShowingThumb = Convert.ToBoolean( saParsed[ 0 ] );
			m_nPosition = Convert.ToInt32( saParsed[ 1 ] );
			m_nPageSize = Convert.ToInt32( saParsed[ 2 ] );
			m_nStart = Convert.ToInt32( saParsed[ 3 ] );
			m_nEnd = Convert.ToInt32( saParsed[ 4 ] );

			if( saParsed.Length > 13 )
			{
				m_nSmallChange = Convert.ToInt32( saParsed[ 5 ] );
				m_nLargeChange = Convert.ToInt32( saParsed[ 6 ] );
				i = 7;
			}

			for( ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}


		public override void Render()
		{
			ControlState oState = ControlState.Normal;


			if (Visible == false)
			{
				oState = ControlState.Hidden;
			}
			else if ( (Enabled == false) || (m_bShowingThumb == false) )
			{
				oState = ControlState.Disabled;
			}
			else if (m_bIsMouseOver)
			{
				oState = ControlState.MouseOver;
			}
			else if (m_oForm.ControlWithFocus == this)
			{
				oState = ControlState.Focus;
			}

			if( Visible == true )
			{
				base.Render();
			}


			float blendRate = (oState == ControlState.Pressed) ? 0.0f : 0.8f;

			// Track 
			m_oTrackLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oTrackRect,m_oTrackLayer_TextureState.Current.ToArgb(),m_oTrackLayer_TextureRect );

			// Up arrow
			m_oLeftArrowLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oLeftButtonRect,m_oLeftArrowLayer_TextureState.Current.ToArgb(),m_oLeftArrowLayer_TextureRect );

			// Down arrow
			m_oRightArrowLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oRightButtonRect,m_oRightArrowLayer_TextureState.Current.ToArgb(),m_oRightArrowLayer_TextureRect );

			// Thumb button
			m_oThumbLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oThumbRect,m_oThumbLayer_TextureState.Current.ToArgb(),m_oThumbLayer_TextureRect );
		}


		public override void OnResize()
		{
			// Get the bounding box first
			//base.UpdateRectangles();

			// Make sure buttons are square
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			m_oLeftButtonRect = new System.Drawing.Rectangle(boundingBox.Location,
										new System.Drawing.Size(boundingBox.Height, boundingBox.Height));

			m_oRightButtonRect = new System.Drawing.Rectangle(boundingBox.Right - boundingBox.Height,boundingBox.Top,
															boundingBox.Height, boundingBox.Height);

			m_oTrackRect = new System.Drawing.Rectangle(m_oLeftButtonRect.Right, m_oLeftButtonRect.Top, 
				m_oRightButtonRect.Left - m_oLeftButtonRect.Right, boundingBox.Height);

			m_oThumbRect = m_oLeftButtonRect;

			UpdateThumbRectangle();
		}

		protected void Cap()
		{
			if (m_nPosition < m_nStart || m_nEnd - m_nStart <= m_nPageSize)
			{
				m_nPosition = m_nStart;
			}
			else if (m_nPosition + m_nPageSize > m_nEnd)
				m_nPosition = m_nEnd - m_nPageSize;
		}

		protected void UpdateThumbRectangle()
		{
			if (m_nEnd - m_nStart > m_nPageSize)
			{
				int thumbWidth = Math.Max(m_oTrackRect.Width * m_nPageSize / (m_nEnd-m_nStart), m_cMinimumThumbSize);
				int maxPosition = m_nEnd - m_nStart - m_nPageSize;
				m_oThumbRect.Location = new System.Drawing.Point(
							m_oTrackRect.Left + (m_nPosition - m_nStart) * (m_oTrackRect.Width - thumbWidth) / maxPosition,
							m_oThumbRect.Top );
				m_oThumbRect.Size = new System.Drawing.Size(thumbWidth,m_oThumbRect.Height);
				m_bShowingThumb = true;
			}
			else
			{
				// No content to scroll
				m_oThumbRect.Width = 0;
				m_bShowingThumb = false;
			}
		}


		public void Scroll(int delta)
		{
			// Perform scroll
			m_nPosition += delta;
			// Cap m_nPosition
			Cap();
			// Update thumb rectangle
			UpdateThumbRectangle();
		}

		public void ShowItem(int index)
		{
			// Cap the index
			if (index < 0)
				index = 0;

			if (index >= m_nEnd)
				index = m_nEnd - 1;

			// Adjust the m_nPosition to show this item
			if (m_nPosition > index)
				m_nPosition = index;
			else if (m_nPosition + m_nPageSize <= index)
				m_nPosition = index - m_nPageSize + 1;

			// Update thumbs again
			UpdateThumbRectangle();
		}

		public void SetTrackRange(int startRange, int endRange)
		{
			m_nStart = startRange; 
			m_nEnd = endRange;
			Cap();
			UpdateThumbRectangle();
		}

		
		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseDown( vMousePosInControlSpace,nButton );

				// Check for on up button
				if (m_oLeftButtonRect.Contains(	(int)(vMousePosInControlSpace.X + this.Location.X),
												(int)(vMousePosInControlSpace.Y + this.Location.Y) ))
				{
					m_nPosition -= m_nSmallChange;
					m_nPosition = DSMisc.Max( m_nStart,m_nPosition );
					UpdateThumbRectangle();
				}
				// Check for on down button
				else if (m_oRightButtonRect.Contains((int)(vMousePosInControlSpace.X + this.Location.X),
													 (int)(vMousePosInControlSpace.Y + this.Location.Y) ))
				{
					m_nPosition += m_nSmallChange;
					m_nPosition = DSMisc.Min( m_nEnd - m_nPageSize,m_nPosition );
					UpdateThumbRectangle();
				}
				// Check for click on thumb
				else if (m_oThumbRect.Contains(	(int)(vMousePosInControlSpace.X + this.Location.X),
												(int)(vMousePosInControlSpace.Y + this.Location.Y) ))
				{
					m_bIsDragging = true;
					m_nThumbOffsetX = (int)vMousePosInControlSpace.X - m_oThumbRect.Left;
				}
				// check for click on track
				else if( m_oThumbRect.Left <= vMousePosInControlSpace.X &&
						 m_oThumbRect.Right > vMousePosInControlSpace.X)
				{
					if (m_oThumbRect.Top > vMousePosInControlSpace.Y &&
						m_oTrackRect.Top <= vMousePosInControlSpace.Y)
					{
						Scroll(-(m_nPageSize-1));
					}
					else if( m_oThumbRect.Bottom <= vMousePosInControlSpace.Y &&
							 m_oTrackRect.Bottom > vMousePosInControlSpace.Y)
					{
						Scroll(m_nPageSize-1);
					}
				}
				//They clicked in the track but not on the button
				else if( m_oTrackRect.Contains(	(int)(vMousePosInControlSpace.X + this.Location.X),
												(int)(vMousePosInControlSpace.Y + this.Location.Y) ))
				{
					if( (int)( vMousePosInControlSpace.X + this.Location.X ) < m_oThumbRect.X )
					{
						m_nPosition -= m_nLargeChange;
						m_nPosition = DSMisc.Max( m_nStart,m_nPosition );
					}
					else
					{
						m_nPosition += m_nLargeChange;
						m_nPosition = DSMisc.Min( m_nEnd - m_nPageSize,m_nPosition );
					}
				}

				bActionWasUsed = true;
			}

			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseUp( vMousePosInControlSpace,nButton );

				m_bIsDragging = false;
				bActionWasUsed = true;
				UpdateThumbRectangle();
			}

			return( bActionWasUsed );
		}

		public override bool OnMouseMove( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				base.OnMouseMove( vMousePosInControlSpace,baButtons );

				if (m_bIsDragging)
				{
					// Calculate new bottom and top of thumb rect
					int right = m_oThumbRect.Right + ((int)vMousePosInControlSpace.X - m_nThumbOffsetX - m_oThumbRect.Left);
					int left = (int)vMousePosInControlSpace.X - m_nThumbOffsetX;
					m_oThumbRect = new System.Drawing.Rectangle( left, m_oThumbRect.Top, right - left, m_oThumbRect.Height);
					if (m_oThumbRect.Left < m_oTrackRect.Left)
						m_oThumbRect.Offset( m_oTrackRect.Left - m_oThumbRect.Left,0 );
					else if (m_oThumbRect.Right > m_oTrackRect.Right)
						m_oThumbRect.Offset( m_oTrackRect.Right - m_oThumbRect.Right,0 );

					// Compute first item index based on thumb m_nPosition
					int maxFirstItem = m_nEnd - m_nStart - m_nPageSize; // Largest possible index for first item
					int maxThumb = m_oTrackRect.Width - m_oThumbRect.Width; // Largest possible thumb m_nPosition

					m_nPosition = m_nStart + (m_oThumbRect.Left - m_oTrackRect.Left +
								  maxThumb / (maxFirstItem * 2) ) * // Shift by half a row to avoid last row covered
								  maxFirstItem / maxThumb;

					bActionWasUsed = true;
				}
			}

			return( bActionWasUsed );
		}



		#region Properties
		public int StartRange
		{
			get
			{
				return( m_nStart );
			}
		}
		public int EndRange
		{
			get
			{
				return( m_nEnd );
			}
		}
		public int TrackPosition
		{
			get { return m_nPosition; }
			set { m_nPosition = value; Cap(); UpdateThumbRectangle(); }
		}

		public int PageSize
		{
			get { return m_nPageSize; }
			set { m_nPageSize = value; Cap(); UpdateThumbRectangle(); }
		}
		public int SmallChange
		{
			get 
			{ 
				return( m_nSmallChange ); 
			}
			set 
			{ 
				m_nSmallChange = value; 
			}
		}
		public int LargeChange
		{
			get 
			{ 
				return( m_nLargeChange ); 
			}
			set 
			{ 
				m_nLargeChange = value; 
			}
		}
		#endregion
	}
	#endregion

	#region ComboBox Control
	public struct ComboBoxItem
	{
		public string ItemText;
		public object ItemData;
		public System.Drawing.Rectangle ItemRect;
		public bool IsItemVisible;
	}

	public class DSComboBox : DSButton
	{
		#region Properties
		protected BlendColor m_oMainLayer_TextureState = new BlendColor();
		protected BlendColor m_oMainLayer_FontColor = new BlendColor();
		protected System.Drawing.Rectangle m_oMainLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected new DrawTextFormat m_oTextFormat = DrawTextFormat.Center | DrawTextFormat.VerticalCenter;

		protected BlendColor m_oButtonLayer_TextureState = new BlendColor();
		protected System.Drawing.Rectangle m_oButtonLayer_TextureRect; // Bounding rectangle of this element on the composite texture

		protected BlendColor m_oDropdownLayer_TextureState = new BlendColor();
		protected BlendColor m_oDropdownLayer_FontColor = new BlendColor();
		protected System.Drawing.Rectangle m_oDropdownLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected DrawTextFormat textDropdownFormat = DrawTextFormat.Left | DrawTextFormat.VerticalCenter;

		protected BlendColor m_oSelectionLayer_TextureState;
		protected BlendColor m_oSelectionLayer_FontColor;
		protected System.Drawing.Rectangle m_oSelectionLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected DrawTextFormat textSelectionFormat = DrawTextFormat.Left | DrawTextFormat.VerticalCenter;

		public const int m_cMainLayer = 0;
		public const int m_cComboButtonLayer = 1;
		public const int m_cDropdownLayer = 2;
		public const int m_cSelectionLayer = 3;

		#region Event code
		public event EventHandler Changed;
		protected void RaiseChangedEvent(DSComboBox sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			// m_bEnabled
			if ( !wasTriggeredByUser)
				return;

			// Fire both the changed and clicked event
			base.RaiseClickEvent(sender, wasTriggeredByUser);
			if (Changed != null)
				Changed(sender, EventArgs.Empty);
		}
		#endregion		

		protected int m_nSelectedIndex = -1;
		protected int m_nFocusedIndex = -1;
		protected int m_nDropHeight = 100;
		protected DSVertScrollBar m_oScrollbarControl;
		private bool m_bIsScrollBarInit = false;
		protected int m_nScrollWidth = 16;
		protected bool m_bIsComboOpen;
		protected System.Drawing.Rectangle m_oTextRect;
		protected System.Drawing.Rectangle m_oButtonRect;
		protected System.Drawing.Rectangle dropDownRect;
		protected System.Drawing.Rectangle dropDownTextRect;
		protected ArrayList m_oaItemList;
		#endregion


		public DSComboBox( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );

			m_oScrollbarControl = new DSVertScrollBar(oForms,oForm);

			// Create the item list array
			m_oaItemList = new ArrayList();

			m_oMainLayer_TextureState.Initialize(DSForm.WhiteColorValue);
			m_oMainLayer_TextureState.States[(int)ControlState.Normal] = new ColorValue(0.8f, 0.8f, 0.8f, 0.55f);
			m_oMainLayer_TextureState.States[(int)ControlState.Focus] = new ColorValue(0.95f, 0.95f, 0.95f, 0.6f);
			m_oMainLayer_TextureState.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.25f);
			m_oMainLayer_TextureRect = new System.Drawing.Rectangle(7,81, 240, 42);
			m_oMainLayer_FontColor.Initialize( oFontColor );
			m_oMainLayer_FontColor.States[(int)ControlState.MouseOver] = new ColorValue(0,0,0,1.0f);
			m_oMainLayer_FontColor.States[(int)ControlState.Pressed] = new ColorValue(0,0,0,1.0f);
			m_oMainLayer_FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.8f);

			m_oButtonLayer_TextureState.Initialize(DSForm.WhiteColorValue);
			m_oButtonLayer_TextureState.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
			m_oButtonLayer_TextureState.States[(int)ControlState.Pressed] = new ColorValue(0.55f, 0.55f, 0.55f, 1.0f);
			m_oButtonLayer_TextureState.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.75f);
			m_oButtonLayer_TextureState.States[(int)ControlState.Disabled] = new ColorValue(1.0f, 1.0f, 1.0f, 0.25f);
			m_oButtonLayer_TextureRect = new System.Drawing.Rectangle(272,0, 53, 49);

			m_oDropdownLayer_TextureState.Initialize(DSForm.WhiteColorValue);
			m_oDropdownLayer_TextureRect = new System.Drawing.Rectangle(7,123,234,142);
			m_oDropdownLayer_FontColor.Initialize( oFontColor );

			m_oSelectionLayer_TextureState.Initialize(DSForm.WhiteColorValue);
			m_oSelectionLayer_TextureRect = new System.Drawing.Rectangle(7,266,234,23);
			m_oSelectionLayer_FontColor.Initialize( oFontColor );


			m_oMainLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
			m_oDropdownLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
			m_oSelectionLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;

			m_oMainLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
			m_oDropdownLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
			m_oSelectionLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
		}


		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() + m_cSEP +
					  m_oScrollbarControl.Serialize() + m_cSEP + 
					  m_nSelectedIndex.ToString() + m_cSEP +
					  m_nFocusedIndex.ToString() + m_cSEP +
					  m_nDropHeight.ToString() + m_cSEP +
					  m_nScrollWidth.ToString() + m_cSEP + 
					  m_bIsComboOpen.ToString(); 

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;


			sRecordLeft = base.DeSerialize( sRecord );
			sRecordLeft = m_oScrollbarControl.DeSerialize( sRecordLeft );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			m_nSelectedIndex = Convert.ToInt32( saParsed[ 0 ] );
			m_nFocusedIndex = Convert.ToInt32( saParsed[ 1 ] );
			m_nDropHeight = Convert.ToInt32( saParsed[ 2 ] );
			m_nScrollWidth = Convert.ToInt32( saParsed[ 3 ] );
			m_bIsComboOpen = Convert.ToBoolean( saParsed[ 4 ] );

			for( int i=5 ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}


		public override bool ContainsPoint(Point oPointInFormSpace)
		{
			if( m_bIsComboOpen == true && dropDownRect.Contains(oPointInFormSpace) == true )
			{
				return( true );
			}
			else
			{
				if( oPointInFormSpace.X >= this.Location.X && oPointInFormSpace.Y >= this.Location.Y &&
					oPointInFormSpace.X <= this.Location.X + this.Size.X &&
					oPointInFormSpace.Y <= this.Location.Y + this.Size.Y )
				{
					return( true ); 
				}
				else
				{
					return( false ); 
				}
			}

			//return base.ContainsPoint (oPointInFormSpace);
		}

		public override void OnResize()
		{
			base.OnResize();

			// Update the bounding box for the items
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			m_oButtonRect = new System.Drawing.Rectangle(boundingBox.Right - boundingBox.Height, boundingBox.Top,
								boundingBox.Height, boundingBox.Height);

			m_oTextRect = boundingBox;
			m_oTextRect.Size = new System.Drawing.Size(m_oTextRect.Width - m_oButtonRect.Width, m_oTextRect.Height);

			dropDownRect = m_oTextRect;
			dropDownRect.Offset(0, (int)(0.9f * m_oTextRect.Height));
			dropDownRect.Size = new System.Drawing.Size(dropDownRect.Width - m_nScrollWidth, dropDownRect.Height + m_nDropHeight);

			// Scale it down slightly
			System.Drawing.Point loc = dropDownRect.Location;
			System.Drawing.Size size = dropDownRect.Size;

			loc.X += (int)(0.1f * dropDownRect.Width);
			loc.Y += (int)(0.1f * dropDownRect.Height);
			size.Width -= (2 * (int)(0.1f * dropDownRect.Width));
			size.Height -= (2 * (int)(0.1f * dropDownRect.Height));

			dropDownTextRect = new System.Drawing.Rectangle(loc, size);

			// Update the scroll bars rects too
			m_oScrollbarControl.Location = new System.Drawing.Point( dropDownRect.Right, dropDownRect.Top + 2 );
			m_oScrollbarControl.Size = new Vector2( m_nScrollWidth, dropDownRect.Height - 2 );
			m_oScrollbarControl.PageSize = (int)(dropDownTextRect.Height / DSResourceManager.GetGlobalInstance().GetFontSize().Y);
			
			// The selected item may have been scrolled off the page.
			// Ensure that it is in page again.
			m_oScrollbarControl.ShowItem(m_nSelectedIndex);
		}

		
		public override void OnFocusOut()
		{
			// Call base first
			base.OnFocusOut ();
			m_bIsComboOpen = false;
		}

		public override void OnHotKey()
		{
			if (m_bIsComboOpen)
				return; // Nothing to do yet

			if (m_nSelectedIndex == -1)
				return; // Nothing selected

			m_nSelectedIndex++;
			if (m_nSelectedIndex >= m_oaItemList.Count)
				m_nSelectedIndex = 0;

			m_nFocusedIndex = m_nSelectedIndex;
			RaiseChangedEvent(this, true);
		}


		public override bool OnMouseWheelMove( long nDirection )
		{
			bool bActionWasUsed = false;

			//Chris
			//int zdelta = (short)NativeMethods.HiWord((uint)wParam.ToInt32()) / DSForm.WheelDelta;
			int zdelta = (int)nDirection;
			if (m_bIsComboOpen)
			{
				m_oScrollbarControl.Scroll(-zdelta * System.Windows.Forms.SystemInformation.MouseWheelScrollLines);
			}
			else
			{
				if (zdelta > 0)
				{
					if (m_nFocusedIndex > 0)
					{
						m_nFocusedIndex--;
						m_nSelectedIndex = m_nFocusedIndex;
						if (!m_bIsComboOpen)
						{
							RaiseChangedEvent(this, true);
						}
					}
				}
				else
				{
					if (m_nFocusedIndex +1 < NumberItems)
					{
						m_nFocusedIndex++;
						m_nSelectedIndex = m_nFocusedIndex;
						if (!m_bIsComboOpen)
						{
							RaiseChangedEvent(this, true);
						}
					}
				}
			}

			return( bActionWasUsed );
		}
		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				//if (ContainsPoint(new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y)))
				if( vMousePosInControlSpace.Y < this.Size.Y )
				{
					// Pressed while inside the control
					m_bIsPressed = true;
					//NativeMethods.SetCapture(Parent.SampleFramework.Window);

					//if (!m_oForm.ControlWithFocus == this)
					//	DSForm.RequestFocus(this);

					// Toggle dropdown
					if (m_oForm.ControlWithFocus == this)
					{
						m_bIsComboOpen = !m_bIsComboOpen;
						if (!m_bIsComboOpen)
						{
							//if (!parentDialog.IsUsingKeyboardInput)
							//DSForm.ClearFocus();
						}
					}
				}

				// Perhaps this click is within the dropdown
				else if (m_bIsComboOpen && dropDownRect.Contains(new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y)))
				{
					// Determine which item has been selected
					for (int i = m_oScrollbarControl.TrackPosition; i < m_oaItemList.Count; i++)
					{
						ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[i];
						if (cbi.IsItemVisible && cbi.ItemRect.Contains(new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y)))
						{
							m_nSelectedIndex = m_nFocusedIndex = i;
							RaiseChangedEvent(this, true);

							m_bIsComboOpen = false;

							//if (!parentDialog.IsUsingKeyboardInput)
							//DSForm.ClearFocus();

							break;
						}
					}
				}
					// Mouse click not on main control or in dropdown, fire an event if needed
				else if (m_bIsComboOpen)
				{
					m_nFocusedIndex = m_nSelectedIndex;
					RaiseChangedEvent(this, true);
					m_bIsComboOpen = false;
				}

				// Make sure the control is no longer 'pressed'
				m_bIsPressed = false;

				// Release focus if appropriate
				//if (!parentDialog.IsUsingKeyboardInput)
				//DSForm.ClearFocus();
			}
		
			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if (m_bIsPressed )//&& ContainsPoint(new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y)))
				{
					// Button click
					m_bIsPressed = false;
				}
			}
		
			return( bActionWasUsed );
		}

		public override bool OnMouseMove( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if (m_bIsComboOpen && dropDownRect.Contains(new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y)))
				{
					// Determine which item has been selected
					for (int i = 0; i < m_oaItemList.Count; i++)
					{
						ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[i];
						if (cbi.IsItemVisible && cbi.ItemRect.Contains(new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y)))
						{
							m_nFocusedIndex = i;
						}
					}
				}
			}
		
			return( bActionWasUsed );
		}

		
		public override bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if( oKey == Microsoft.DirectX.DirectInput.Key.Return )
				{
					if (m_bIsComboOpen)
					{
						if (m_nSelectedIndex != m_nFocusedIndex)
						{
							m_nSelectedIndex = m_nFocusedIndex;
							RaiseChangedEvent(this, true);
						}
						m_bIsComboOpen = false;

						//if (!Parent.IsUsingKeyboardInput)
						//DSForm.ClearFocus();
					}
			
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.F4 )
				{
					//Chris
					// Filter out auto repeats
					//if ((lParam.ToInt32() & RepeatMask) != 0)
					//	return ;

					m_bIsComboOpen = !m_bIsComboOpen;
					if (!m_bIsComboOpen)
					{
						RaiseChangedEvent(this, true);

						//if (!Parent.IsUsingKeyboardInput)
						//DSForm.ClearFocus();
					}
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Left || oKey == Microsoft.DirectX.DirectInput.Key.Up )
				{
					if (m_nFocusedIndex > 0)
					{
						m_nFocusedIndex--;
						m_nSelectedIndex = m_nFocusedIndex;
						if (!m_bIsComboOpen)
							RaiseChangedEvent(this, true);
					}
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Right || oKey == Microsoft.DirectX.DirectInput.Key.Down )
				{
					if (m_nFocusedIndex + 1 < (int)NumberItems)
					{
						m_nFocusedIndex++;
						m_nSelectedIndex = m_nFocusedIndex;
						if (!m_bIsComboOpen)
							RaiseChangedEvent(this, true);
					}
				}
			}
		
			return( bActionWasUsed );
		}


		public override void Render()
		{
			ControlState oState = ControlState.Normal;
			if (!m_bIsComboOpen)
				oState = ControlState.Hidden;

			if( Visible == true )
			{
				base.Render();
			}


			// If we have not initialized the scroll bar page size,
			// do that now.
			if (!m_bIsScrollBarInit)
			{
				m_oScrollbarControl.PageSize = (int)(dropDownTextRect.Height / DSResourceManager.GetGlobalInstance().GetFontSize().Y);

				m_bIsScrollBarInit = true;
			}

			if (m_bIsComboOpen)
				m_oScrollbarControl.Render();

			//Drop down layer
			// Blend current color
			m_oDropdownLayer_TextureState.Blend(oState, m_dElapsedTime);
			m_oDropdownLayer_FontColor.Blend(oState, m_dElapsedTime);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,dropDownRect,m_oDropdownLayer_TextureState.Current.ToArgb(),m_oDropdownLayer_TextureRect );

			// Selection layer
			//Element selectionElement = elementList[ComboBox.m_cSelectionLayer] as Element;
			m_oSelectionLayer_TextureState.Current = m_oDropdownLayer_TextureState.Current;
			m_oSelectionLayer_FontColor.Current = m_oSelectionLayer_FontColor.States[(int)ControlState.Normal];

			int currentY = dropDownTextRect.Top;
			int remainingHeight = dropDownTextRect.Height;

			for (int i = m_oScrollbarControl.TrackPosition; i < m_oaItemList.Count; i++)
			{
				ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[i];

				// Make sure there's room left in the dropdown
				remainingHeight -= (int)DSResourceManager.GetGlobalInstance().GetFontSize().Y;
				if (remainingHeight < 0)
				{
					// Not m_bVisible, store that item
					cbi.IsItemVisible = false;
					m_oaItemList[i] = cbi; // Store this back in list
					continue;
				}

				cbi.ItemRect = new System.Drawing.Rectangle(dropDownTextRect.Left, currentY,
					dropDownTextRect.Width, (int)DSResourceManager.GetGlobalInstance().GetFontSize().Y);
				cbi.IsItemVisible = true;
				currentY += (int)DSResourceManager.GetGlobalInstance().GetFontSize().Y;
				m_oaItemList[i] = cbi; // Store this back in list

				if (m_bIsComboOpen)
				{
					if (m_nFocusedIndex == i)
					{
						System.Drawing.Rectangle rect = new System.Drawing.Rectangle(
							dropDownRect.Left, cbi.ItemRect.Top - 2, dropDownRect.Width,
							cbi.ItemRect.Height + 4);
						m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,rect,m_oSelectionLayer_TextureState.Current.ToArgb(),m_oSelectionLayer_TextureRect );
						m_oForm.RenderText( base.Font,cbi.ItemText,  cbi.ItemRect,m_oSelectionLayer_FontColor,textDropdownFormat );
					}
					else
					{
						m_oForm.RenderText(base.Font,cbi.ItemText,  cbi.ItemRect,m_oDropdownLayer_FontColor,textDropdownFormat );
					}
				}
			}

			int offsetX = 0;
			int offsetY = 0;

			oState = ControlState.Normal;
			if (Visible == false)
				oState = ControlState.Hidden;
			else if (Enabled == false)
				oState = ControlState.Disabled;
			else if (m_bIsPressed)
			{
				oState = ControlState.Pressed;
				offsetX = 1;
				offsetY = 2;
			}
			else if (m_bIsMouseOver)
			{
				oState = ControlState.MouseOver;
				offsetX = -1;
				offsetY = -2;
			}
			else if (m_oForm.ControlWithFocus == this)
				oState = ControlState.Focus;

			float blendRate = (oState == ControlState.Pressed) ? 0.0f : 0.8f;

			// Button
			// Blend current color
			m_oButtonLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
            
			System.Drawing.Rectangle windowRect = m_oButtonRect;
			windowRect.Offset(offsetX, offsetY);
			// Draw sprite
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,windowRect,m_oButtonLayer_TextureState.Current.ToArgb(),m_oButtonLayer_TextureRect );

			if (m_bIsComboOpen)
				oState = ControlState.Pressed;

			// Main text box
			// Blend current color
			m_oMainLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oMainLayer_FontColor.Blend(oState, m_dElapsedTime, blendRate);

			// Draw sprite
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oTextRect,m_oMainLayer_TextureState.Current.ToArgb(),m_oMainLayer_TextureRect );

			if (m_nSelectedIndex >= 0 && m_nSelectedIndex < m_oaItemList.Count)
			{
				try
				{
					ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[m_nSelectedIndex];
					m_oForm.RenderText( base.Font,cbi.ItemText,  m_oTextRect,m_oMainLayer_FontColor,m_oTextFormat );
				}
				catch {} // Ignore
			}

		}

		public override void FrameMove( double dElapsedTime,double dAppTime )
		{
			try
			{
				base.FrameMove( dElapsedTime,dAppTime );

				if( m_bIsScrollBarInit == true )
				{
					m_oScrollbarControl.FrameMove( dElapsedTime,dAppTime );
				}
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}
		}



		#region Item Controlling methods
		public int NumberItems { get { return m_oaItemList.Count; } }
		public ComboBoxItem this[int index]
		{
			get { return (ComboBoxItem)m_oaItemList[index]; }
		}

		public void AddItem(string text, object data)
		{
			if ((text == null) || (text.Length == 0))
				throw new ArgumentNullException("text", "You must pass in a valid item name when adding a new item.");

			// Create a new item and add it
			ComboBoxItem newitem = new ComboBoxItem();
			newitem.ItemText = text;
			newitem.ItemData = data;
			m_oaItemList.Add(newitem);

			// Update the scrollbar with the new range
			m_oScrollbarControl.SetTrackRange(0, m_oaItemList.Count);

			// If this is the only item in the list, it should be selected
			if (NumberItems == 1)
			{
				m_nSelectedIndex = 0;
				m_nFocusedIndex = 0;
				RaiseChangedEvent(this, false);
			}
		}

		/// <summary>Removes an item at a particular index</summary>
		public void RemoveAt(int index)
		{
			// Remove the item
			m_oaItemList.RemoveAt(index);

			// Update the scrollbar with the new range
			m_oScrollbarControl.SetTrackRange(0, m_oaItemList.Count);

			if (m_nSelectedIndex >= m_oaItemList.Count)
				m_nSelectedIndex = m_oaItemList.Count - 1;
		}

		/// <summary>Removes all items from the control</summary>
		public void Clear()
		{
			// clear the list
			m_oaItemList.Clear();

			// Update scroll bar and index
			m_oScrollbarControl.SetTrackRange(0, 1);
			m_nFocusedIndex = m_nSelectedIndex = -1;
		}

		/// <summary>Determines whether this control contains an item</summary>
		public bool ContainsItem(string text, int m_nStart)
		{
			return (FindItem(text, m_nStart) != -1);
		}
		/// <summary>Determines whether this control contains an item</summary>
		public bool ContainsItem(string text) { return ContainsItem(text, 0); }

		/// <summary>Gets the data for the selected item</summary>
		public object GetSelectedData()
		{
			if (m_nSelectedIndex < 0)
				return null; // Nothing selected

			ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[m_nSelectedIndex];
			return cbi.ItemData;
		}

		/// <summary>Gets the selected item</summary>
		public ComboBoxItem GetSelectedItem()
		{
			if (m_nSelectedIndex < 0)
				throw new ArgumentOutOfRangeException("m_nSelectedIndex", "No item selected.");

			return (ComboBoxItem)m_oaItemList[m_nSelectedIndex];
		}

		/// <summary>Gets the data for an item</summary>
		public object GetItemData(string text)
		{
			int index = FindItem(text);
			if (index == -1)
				return null; // no item

			ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[index];
			return cbi.ItemData;
		}

		/// <summary>Finds an item in the list and returns the index</summary>
		protected int FindItem(string text, int m_nStart)
		{
			if ((text == null) || (text.Length == 0))
				return -1;

			for(int i = m_nStart; i < m_oaItemList.Count; i++)
			{
				ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[i];
				if (string.Compare(cbi.ItemText, text, true) == 0)
				{
					return i;
				}
			}

			// Never found it
			return -1;
		}
		/// <summary>Finds an item in the list and returns the index</summary>
		protected int FindItem(string text) { return FindItem(text, 0); }

		/// <summary>Sets the selected item by index</summary>
		public void SetSelected(int index)
		{
			if (index >= NumberItems)
				throw new ArgumentOutOfRangeException("index", "There are not enough items in the list to select this index.");

			m_nFocusedIndex = m_nSelectedIndex = index;
			RaiseChangedEvent(this, false);
		}

		/// <summary>Sets the selected item by text</summary>
		public void SetSelected(string text)
		{
			if ((text == null) || (text.Length == 0))
				throw new ArgumentNullException("text", "You must pass in a valid item name when adding a new item.");

			int index = FindItem(text);
			if (index == -1)
				throw new InvalidOperationException("This item could not be found.");

			m_nFocusedIndex = m_nSelectedIndex = index;
			RaiseChangedEvent(this, false);
		}

		/// <summary>Sets the selected item by data</summary>
		public void SetSelectedByData(object data)
		{
			for (int index = 0; index < m_oaItemList.Count; index++)
			{
				ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[index];
				if (cbi.ItemData.ToString().Equals(data.ToString()))
				{
					m_nFocusedIndex = m_nSelectedIndex = index;
					RaiseChangedEvent(this, false);
				}
			}

			// Could not find this item.  Uncomment line below for debug information
			//System.Diagnostics.Debugger.Log(9,string.Empty, "Could not find an object with this data.\r\n");
		}

		#endregion


		#region Properties
		public override bool CanHaveFocus { get { return (Visible && Enabled); } }
		public int Height
		{ 
			set
			{
				m_nDropHeight = value;
				OnResize(); 
			}
			get
			{
				return( m_nDropHeight );
			}
		}
		public int ScrollbarWidth
		{ 
			set
			{
				m_nScrollWidth = value;
				OnResize(); 
			}
			get
			{
				return( m_nScrollWidth );
			}
		}
		public override DSGraphicsWrapper DSGraphicsWrapper
		{
			get
			{
				return( base.DSGraphicsWrapper );
			}
			set
			{
				base.DSGraphicsWrapper = value;
				m_oScrollbarControl.DSGraphicsWrapper = value;
			}
		}
		public string Text
		{
			get
			{
				string sRetVal = "";

				if (m_nSelectedIndex >= 0 && m_nSelectedIndex < m_oaItemList.Count )
				{
					try
					{
						ComboBoxItem cbi = (ComboBoxItem)m_oaItemList[m_nSelectedIndex];
						sRetVal = cbi.ItemText;
					}
					catch {} // Ignore
				}

				return( sRetVal );
			}
		}
		public bool IsComboOpen
		{
			get
			{
				return( m_bIsComboOpen );
			}
			set
			{
				m_bIsComboOpen = value;
			}
		}
		public override System.Drawing.Color FontColor
		{
			get
			{
				return( base.FontColor );
			}
			set
			{
				base.FontColor = value;
				Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );

				m_oMainLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
				m_oDropdownLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
				m_oSelectionLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;

				m_oMainLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
				m_oDropdownLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
				m_oSelectionLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
			}
		}
		#endregion
	}
	
	#endregion

	#region Slider Control
	public class DSSlider : DSBaseControl
	{
		#region Properties
		protected BlendColor m_oButtonLayer_TextureState = new BlendColor();
		protected BlendColor m_oButtonLayer_FontColor = new BlendColor();
		protected System.Drawing.Rectangle m_oButtonLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected DrawTextFormat textButtonFormat = DrawTextFormat.Left | DrawTextFormat.VerticalCenter;

		protected BlendColor m_oTrackLayer_TextureState = new BlendColor();
		protected BlendColor m_oTrackLayer_FontColor = new BlendColor();
		protected System.Drawing.Rectangle m_oTrackLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected DrawTextFormat textTrackFormat = DrawTextFormat.Left | DrawTextFormat.VerticalCenter;

		public const int m_cTrackLayer = 0;
		public const int m_cButtonLayer = 1;
		
		public event EventHandler ValueChanged;
		protected int m_nCurrentValue = 50; 
		protected int m_nMaxValue = 100;
		protected int m_nMinValue = 0;
        
		protected int m_nDragX; // Mouse m_nPosition at the m_nStart of the drag
		protected int m_nDragOffset; // Drag offset from the center of the button
		protected int m_nButtonX;

		protected bool m_bIsPressed = false;
		protected System.Drawing.Rectangle m_oButtonRect;
		#endregion


		public DSSlider( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			m_oButtonLayer_TextureState.Initialize(DSForm.WhiteColorValue);
			m_oButtonLayer_TextureRect = new System.Drawing.Rectangle(248,55,41,41);

			m_oTrackLayer_TextureState.Initialize(DSForm.WhiteColorValue);
			m_oTrackLayer_TextureState.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
			m_oTrackLayer_TextureState.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.75f);
			m_oTrackLayer_TextureState.States[(int)ControlState.Disabled] = new ColorValue(1.0f, 1.0f, 1.0f, 0.25f);
			m_oTrackLayer_TextureRect = new System.Drawing.Rectangle(1,290,279,41);
		}


		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() + m_cSEP +  
					  m_nCurrentValue.ToString() + m_cSEP + 
					  m_nMaxValue.ToString() + m_cSEP + 
					  m_nMinValue.ToString(); 

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;


			sRecordLeft = base.DeSerialize( sRecord );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			m_nCurrentValue = Convert.ToInt32( saParsed[ 0 ] );
			m_nMaxValue = Convert.ToInt32( saParsed[ 1 ] );
			m_nMinValue = Convert.ToInt32( saParsed[ 2 ] );

			for( int i=1 ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}


		protected void RaiseValueChanged(DSSlider sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			// m_bEnabled
			if ( !wasTriggeredByUser)
				return;

			if (ValueChanged != null)
				ValueChanged(sender, EventArgs.Empty);
		}

		public void SetRange(int min, int max)
		{
			m_nMinValue = min;
			m_nMaxValue = max;
			SetValueInternal(m_nCurrentValue, false);
		}

		protected void SetValueInternal(int newValue, bool fromInput)
		{
			// Clamp to the range
			newValue = Math.Max(m_nMinValue, newValue);
			newValue = Math.Min(m_nMaxValue, newValue);
			if (newValue == m_nCurrentValue)
				return;

			// Update the value, the rects, then fire the events if necessar
			m_nCurrentValue = newValue; 
			OnResize();
			RaiseValueChanged(this, fromInput);
		}

		
		public override bool ContainsPoint(System.Drawing.Point pt)
		{
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			return boundingBox.Contains(pt) || m_oButtonRect.Contains(pt);
		}

		public override void OnResize()
		{
			// Create the button rect
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			m_oButtonRect = boundingBox;
			m_oButtonRect.Width = m_oButtonRect.Height; // Make it square

			// Offset it 
			m_oButtonRect.Offset(-m_oButtonRect.Width / 2, 0);
			m_nButtonX = (int)((m_nCurrentValue - m_nMinValue) * (float)boundingBox.Width / (m_nMaxValue - m_nMinValue) );
			m_oButtonRect.Offset(m_nButtonX, 0);
		}

		public int ValueFromPosition(int x)
		{
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			float valuePerPixel = ((float)(m_nMaxValue - m_nMinValue) / (float)boundingBox.Width);
			return (int)(0.5f + m_nMinValue + valuePerPixel * (x - boundingBox.Left));
		}


		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );

			if( Enabled == true && Visible == true )
			{
				if (m_oButtonRect.Contains(new Point((int)vMousePosInControlSpace.X+(int)this.Location.X,(int)vMousePosInControlSpace.Y+(int)this.Location.Y) ))
				{
					// Pressed while inside the control
					m_bIsPressed = true;
					//NativeMethods.SetCapture(Parent.SampleFramework.Window);

					m_nDragX = (int)vMousePosInControlSpace.X;
					m_nDragOffset = m_nButtonX - m_nDragX;
					//if (!m_oForm.ControlWithFocus == this)
					//	DSForm.RequestFocus(this);
				}
				else if (boundingBox.Contains(new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y)))
				{
					if (vMousePosInControlSpace.X > m_nButtonX + base.m_vPos.X)
					{
						SetValueInternal(m_nCurrentValue + 1, true);
					}
					else if (vMousePosInControlSpace.X < m_nButtonX + m_vPos.X)
					{
						SetValueInternal(m_nCurrentValue - 1, true);
					}
				}
			}
		
			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				m_bIsPressed = false;
				//NativeMethods.ReleaseCapture();
				//DSForm.ClearFocus();
				//RaiseValueChanged(this, true);
			}
		
			return( bActionWasUsed );
		}

		public override bool OnMouseMove( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if (m_bIsPressed)
				{
					SetValueInternal(ValueFromPosition((int)m_vPos.X + (int)vMousePosInControlSpace.X + m_nDragOffset), true);
				}
			}
		
			return( bActionWasUsed );
		}


		public override bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if( oKey == Microsoft.DirectX.DirectInput.Key.Home )
				{
					SetValueInternal(m_nMinValue, true);
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.End )
				{
					SetValueInternal(m_nMaxValue, true);
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Prior ||
					oKey == Microsoft.DirectX.DirectInput.Key.Left ||
					oKey == Microsoft.DirectX.DirectInput.Key.Up )
				{
					SetValueInternal(m_nCurrentValue - 1, true);
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Next ||
					oKey == Microsoft.DirectX.DirectInput.Key.Right ||
					oKey == Microsoft.DirectX.DirectInput.Key.Down )
				{
					SetValueInternal(m_nCurrentValue + 1, true);
				}
			}
		
			return( bActionWasUsed );
		}

    
		public override void Render()
		{
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );

			ControlState oState = ControlState.Normal;
			if (Visible == false)
			{
				oState = ControlState.Hidden;
			}
			else if (Enabled == false)
			{
				oState = ControlState.Disabled;
			}
			else if (m_bIsPressed)
			{
				oState = ControlState.Pressed;
			}
			else if (m_bIsMouseOver)
			{
				oState = ControlState.MouseOver;
			}
			else if (m_oForm.ControlWithFocus == this)
			{
				oState = ControlState.Focus;
			}

			if( Visible == true )
			{
				base.Render();
			}

			float blendRate = (oState == ControlState.Pressed) ? 0.0f : 0.8f;
            
			// Blend current color
			m_oTrackLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,boundingBox,m_oTrackLayer_TextureState.Current.ToArgb(),m_oTrackLayer_TextureRect );

			//e = elementList[Slider.m_cButtonLayer] as Element;
			// Blend current color
			m_oButtonLayer_TextureState.Blend(oState, m_dElapsedTime, blendRate);
			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oButtonRect,m_oButtonLayer_TextureState.Current.ToArgb(),m_oButtonLayer_TextureRect );
		}



		#region Properties
		public override bool CanHaveFocus { get { return true; }}
		public int Value { get { return m_nCurrentValue; } set { SetValueInternal(value, false); } }
		#endregion
	}
	#endregion

	#region ListBox Control
	public enum ListBoxStyle
	{
		SingleSelection,
		Multiselection,
		NoSelection
	}

	public struct ListBoxItem
	{
		public string ItemText;
		public object ItemData;
		public System.Drawing.Rectangle ItemRect;
		public bool IsItemSelected;
	}
	public class DSListBox : DSBaseControl
	{
		#region Properties
		protected BlendColor m_oMainLayer_TextureState = new BlendColor();
		protected BlendColor m_oMainLayer_FontColor = new BlendColor();
		protected System.Drawing.Rectangle m_oMainLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected DrawTextFormat m_oTextFormat = DrawTextFormat.Left | DrawTextFormat.Top;

		protected BlendColor m_oSelectionLayer_TextureState = new BlendColor();
		protected BlendColor m_oSelectionLayer_FontColor = new BlendColor();
		protected System.Drawing.Rectangle m_oSelectionLayer_TextureRect; // Bounding rectangle of this element on the composite texture
		protected DrawTextFormat textSelectionFormat = DrawTextFormat.Left | DrawTextFormat.Top;

		public const int m_cMainLayer = 0;
		public const int m_cSelectionLayer = 1;

		#region Event code
		public event EventHandler ContentsChanged;
		public event EventHandler DoubleClick;
		public event EventHandler Selection;
		/// <summary>Raises the contents changed event</summary>
		protected void RaiseContentsChangedEvent(DSListBox sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			// m_bEnabled
			if ( !wasTriggeredByUser)
				return;

			// Fire the event
			if (ContentsChanged != null)
				ContentsChanged(sender, EventArgs.Empty);
		}
		/// <summary>Raises the double click event</summary>
		protected void RaiseDoubleClickEvent(DSListBox sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			// m_bEnabled
			if ( !wasTriggeredByUser)
				return;

			// Fire the event
			if (DoubleClick != null)
				DoubleClick(sender, EventArgs.Empty);
		}
		/// <summary>Raises the selection event</summary>
		protected void RaiseSelectionEvent(DSListBox sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			// m_bEnabled
			if ( !wasTriggeredByUser)
				return;

			// Fire the event
			if (Selection != null)
				Selection(sender, EventArgs.Empty);
		}
		#endregion

		private bool m_bIsScrollBarInit = false;
		protected System.Drawing.Rectangle m_oTextRect; // Text rendering bound
		protected System.Drawing.Rectangle m_oSelectionRect; // Selection box bound
		protected DSVertScrollBar m_oScrollbarControl; 
		protected int m_nScrollWidth = 16;
		protected int m_nBorder = 6;
		protected int m_nMargin = 5;
		protected int m_nTextHeight = 0; // Height of a single line of text
		protected int m_nSelectedIndex = -1;
		protected int m_nSelectedStarted = 0;
		protected bool m_bIsDragging = false;
		protected ListBoxStyle m_oStyle = ListBoxStyle.SingleSelection;
 
		protected ArrayList m_oaItemList;
		#endregion


		public DSListBox( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );

			m_oScrollbarControl = new DSVertScrollBar( m_oForms,m_oForm );

			// Create the item list array
			m_oaItemList = new ArrayList();

			m_oMainLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oMainLayer_TextureRect = new System.Drawing.Rectangle(13,124,228,141);	
			m_oMainLayer_FontColor.Initialize( oFontColor );

			m_oSelectionLayer_TextureState.Initialize( DSForm.WhiteColorValue );
			m_oSelectionLayer_TextureRect = new System.Drawing.Rectangle(17,269,224,18);
			m_oSelectionLayer_FontColor.Initialize( oFontColor );


			m_oMainLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
			m_oSelectionLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;

			m_oMainLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
			m_oSelectionLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
		}


		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() + m_cSEP +
					  m_oScrollbarControl.Serialize() + m_cSEP +
				      m_bIsScrollBarInit.ToString() + m_cSEP + 					  
					  m_nScrollWidth.ToString() + m_cSEP + 
					  m_nBorder.ToString() + m_cSEP + 
					  m_nMargin.ToString() + m_cSEP + 
					  m_nTextHeight.ToString() + m_cSEP + 
					  m_nSelectedIndex.ToString() + m_cSEP + 
					  m_nSelectedStarted.ToString() + m_cSEP;

			if( m_oStyle == ListBoxStyle.Multiselection )
			{
				sRetVal += "Multiselection";
			}
			else
			{
				sRetVal += "SingleSelection";
			}

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;


			sRecordLeft = base.DeSerialize( sRecord );
			sRecordLeft = m_oScrollbarControl.DeSerialize( sRecordLeft );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			m_bIsScrollBarInit = Convert.ToBoolean( saParsed[ 0 ] );
		    m_nScrollWidth = Convert.ToInt32( saParsed[ 1 ] );
			m_nBorder = Convert.ToInt32( saParsed[ 2 ] );
			m_nMargin = Convert.ToInt32( saParsed[ 3 ] );
			m_nTextHeight = Convert.ToInt32( saParsed[ 4 ] );
			//m_nSelectedIndex = Convert.ToInt32( saParsed[ 5 ] );
			//m_nSelectedStarted = Convert.ToInt32( saParsed[ 6 ] );

			if( saParsed[ 7 ] == "Multiselection" )
			{
				m_oStyle = ListBoxStyle.Multiselection;
			}
			else
			{
				m_oStyle = ListBoxStyle.SingleSelection;
			}


			for( int i=8 ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}


		public override void Render()
		{
			if (!Visible)
				return; // Nothing to render
            
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );


			base.Render();

			// Blend current color
			m_oMainLayer_TextureState.Blend(ControlState.Normal, m_dElapsedTime);
			m_oMainLayer_FontColor.Blend(ControlState.Normal, m_dElapsedTime);
            
			// Blend current color
			m_oSelectionLayer_TextureState.Blend(ControlState.Normal, m_dElapsedTime);
			m_oSelectionLayer_FontColor.Blend(ControlState.Normal, m_dElapsedTime);

			m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,boundingBox,m_oMainLayer_TextureState.Current.ToArgb(),m_oMainLayer_TextureRect );

			// Render the text
			if (m_oaItemList.Count > 0)
			{
				// Find out the m_vSize.Y of a single line of text
				System.Drawing.Rectangle rc = m_oTextRect;
				System.Drawing.Rectangle sel = m_oSelectionRect;
				int nFontSize = (int)( DSResourceManager.GetGlobalInstance().GetFontSize().Y );
				rc.Height = nFontSize;//(int)(DialogResourceManager.GetGlobalInstance().GetFontNode((int)e.FontIndex).Height);
				m_nTextHeight = rc.Height;

				// If we have not initialized the scroll bar page size,
				// do that now.
				if (!m_bIsScrollBarInit)
				{
					if (m_nTextHeight > 0)
						m_oScrollbarControl.PageSize = (int)(m_oTextRect.Height / m_nTextHeight);
					else
						m_oScrollbarControl.PageSize = m_oTextRect.Height;

					m_bIsScrollBarInit = true;
				}
				rc.Width = m_oTextRect.Width;
				for (int i = m_oScrollbarControl.TrackPosition; i < m_oaItemList.Count; ++i)
				{
					if (rc.Bottom > m_oTextRect.Bottom)
						break;

					ListBoxItem lb = (ListBoxItem)m_oaItemList[i];

					// Determine if we need to render this item with the
					// selected element.
					bool isSelectedStyle = false;

					if ( (m_nSelectedIndex == i) && (m_oStyle == ListBoxStyle.SingleSelection) )
						isSelectedStyle = true;
					else if (m_oStyle == ListBoxStyle.Multiselection)
					{
						if (m_bIsDragging && ( ( i >= m_nSelectedIndex && i < m_nSelectedStarted) || 
							(i <= m_nSelectedIndex && i > m_nSelectedStarted) ) )
						{
							ListBoxItem selStart = (ListBoxItem)m_oaItemList[m_nSelectedStarted];
							isSelectedStyle = selStart.IsItemSelected;
						}
						else
							isSelectedStyle = lb.IsItemSelected;
					}

					// Now render the text
					if (isSelectedStyle)
					{
						sel.Location = new System.Drawing.Point(sel.Left, rc.Top); 
						sel.Height = rc.Height;
						m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,sel,m_oSelectionLayer_TextureState.Current.ToArgb(),m_oSelectionLayer_TextureRect );
						m_oForm.RenderText( base.Font,lb.ItemText,  rc,m_oSelectionLayer_FontColor ,textSelectionFormat );
					}
					else
						m_oForm.RenderText( base.Font,lb.ItemText, rc,m_oMainLayer_FontColor, m_oTextFormat );

					rc.Offset(0, m_nTextHeight);
				}
			}

			// Render the scrollbar finally
			m_oScrollbarControl.Render();
		}

		public override void FrameMove( double dElapsedTime,double dAppTime )
		{
			try
			{
				base.FrameMove( dElapsedTime,dAppTime );

				if( m_bIsScrollBarInit == true )
				{
					m_oScrollbarControl.FrameMove( dElapsedTime,dAppTime );
				}
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}
		}


		public override void OnResize()
		{
			// Calculate the size of the selection rectangle
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			m_oSelectionRect = boundingBox;
			m_oSelectionRect.Width -= m_nScrollWidth;
			m_oSelectionRect.Inflate(-m_nBorder, -m_nBorder);
			m_oTextRect = m_oSelectionRect;
			m_oTextRect.Inflate(-m_nMargin, 0);

			// Update the scroll bars rects too
			m_oScrollbarControl.Location = new System.Drawing.Point( boundingBox.Right - m_nScrollWidth, boundingBox.Top );
			m_oScrollbarControl.Size = new Vector2( m_nScrollWidth, m_vSize.Y );

			//FontNode fNode = DialogResourceManager.GetGlobalInstance().GetFontNode((int)(elementList[0] as Element).FontIndex);
			//if ((fNode != null) && (fNode.Height > 0))
			//{
			m_oScrollbarControl.PageSize = (int)(m_oTextRect.Height / (int)DSResourceManager.GetGlobalInstance().GetFontSize().Y);

			// The selected item may have been scrolled off the page.
			// Ensure that it is in page again.
			m_oScrollbarControl.ShowItem(m_nSelectedIndex);
			//}
		}
		public override void OnInitialize()
		{
			m_oScrollbarControl.OnInitialize();
		}


		public override bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if( oKey == Microsoft.DirectX.DirectInput.Key.Up || 
					oKey == Microsoft.DirectX.DirectInput.Key.Down ||
					oKey == Microsoft.DirectX.DirectInput.Key.Next ||
					oKey == Microsoft.DirectX.DirectInput.Key.Prior ||
					oKey == Microsoft.DirectX.DirectInput.Key.Home ||
					oKey == Microsoft.DirectX.DirectInput.Key.End )
				{
					// If no items exists, do nothing
					if (m_oaItemList.Count == 0)
						return( bActionWasUsed );

					int oldSelected = m_nSelectedIndex;

					// Adjust m_nSelectedIndex
					if( oKey == Microsoft.DirectX.DirectInput.Key.Up ){--m_nSelectedIndex;}
					if( oKey == Microsoft.DirectX.DirectInput.Key.Down ){++m_nSelectedIndex;}
					if( oKey == Microsoft.DirectX.DirectInput.Key.Next ){m_nSelectedIndex += m_oScrollbarControl.PageSize - 1;}
					if( oKey == Microsoft.DirectX.DirectInput.Key.Prior ){m_nSelectedIndex -= m_oScrollbarControl.PageSize - 1;}
					if( oKey == Microsoft.DirectX.DirectInput.Key.Home ){m_nSelectedIndex = 0;}
					if( oKey == Microsoft.DirectX.DirectInput.Key.End ){m_nSelectedIndex = m_oaItemList.Count - 1;}

					// Clamp the item
					if (m_nSelectedIndex < 0)
						m_nSelectedIndex = 0;
					if (m_nSelectedIndex >= m_oaItemList.Count)
						m_nSelectedIndex = m_oaItemList.Count - 1;

					// Did the selection change?
					if (oldSelected != m_nSelectedIndex)
					{
						if (m_oStyle == ListBoxStyle.Multiselection)
						{
							// Clear all selection
							for(int i = 0; i < m_oaItemList.Count; i++)
							{
								ListBoxItem lbi = (ListBoxItem)m_oaItemList[i];
								lbi.IsItemSelected = false;
								m_oaItemList[i] = lbi;
							}
							//Chris
							// Is shift being held down?
							bool shiftDown = false;
							//((NativeMethods.GetAsyncKeyState((int)System.Windows.Forms.Keys.ShiftKey) & 0x8000) != 0);

							if (shiftDown)
							{
								// Select all items from the m_nStart selection to current selected index
								int m_nEnd = Math.Max(m_nSelectedStarted, m_nSelectedIndex);
								for(int i = Math.Min(m_nSelectedStarted, m_nSelectedIndex); i <= m_nEnd; ++i)
								{
									ListBoxItem lbi = (ListBoxItem)m_oaItemList[i];
									lbi.IsItemSelected = true;
									m_oaItemList[i] = lbi;
								}
							}
							else
							{
								ListBoxItem lbi = (ListBoxItem)m_oaItemList[m_nSelectedIndex];
								lbi.IsItemSelected = true;
								m_oaItemList[m_nSelectedIndex] = lbi;

								// Update selection m_nStart
								m_nSelectedStarted = m_nSelectedIndex;
							}

						}
						else // Update selection m_nStart
							m_nSelectedStarted = m_nSelectedIndex;

						// adjust scrollbar
						m_oScrollbarControl.ShowItem(m_nSelectedIndex);
						RaiseSelectionEvent(this, true);
					}
				}
			}

			return( bActionWasUsed );
		}

		public override bool OnMouseWheelMove( long nDirection )
		{
			bool bActionWasUsed = false;
			//const int ShiftModifier = 0x0004;
			//const int ControlModifier = 0x0008;

			if( Enabled == true && Visible == true )
			{
				// First acquire focus
				//Chris
				//if (msg == NativeMethods.WindowMessage.LeftButtonDown)
				//	if (!hasFocus)
				//		DSForm.RequestFocus(this);


				// Let the scroll bar handle it first
				//if (m_oScrollbarControl.HandleMouse(msg, pt, wParam, lParam))
				//return ;


				//case NativeMethods.WindowMessage.MouseWheel:
				//{
				int lines = System.Windows.Forms.SystemInformation.MouseWheelScrollLines;
				//Chris
				int scrollAmount = 1;//(int)(NativeMethods.HiWord((uint)wParam.ToInt32()) / DSForm.WheelDelta * lines);
				m_oScrollbarControl.Scroll(-scrollAmount);
				//break;
				//}
			}

			return( bActionWasUsed );
		}

		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			Vector2 vScrollPos = new Vector2( 0,0 );
			bool bActionWasUsed = false;


			if( Enabled == true && Visible == true )
			{
				// Check for clicks in the text area
				if( m_oaItemList.Count > 0 && 
					vMousePosInControlSpace.X >= 0 && vMousePosInControlSpace.X <= m_vSize.X &&
					vMousePosInControlSpace.Y >= 0 && vMousePosInControlSpace.Y <= m_vSize.Y &&
					vMousePosInControlSpace.X < m_oScrollbarControl.Location.X - m_oScrollbarControl.Size.X )
				{
					// Compute the index of the clicked item
					int clicked = 0;
					if (m_nTextHeight > 0)
						clicked = m_oScrollbarControl.TrackPosition + ( (int)( vMousePosInControlSpace.Y - (m_oTextRect.Y - base.m_vPos.Y) ) / m_nTextHeight );
					else
						clicked = -1;

					// Only proceed if the click falls ontop of an item
					if (clicked >= m_oScrollbarControl.TrackPosition &&
						clicked < m_oaItemList.Count &&
						clicked < m_oScrollbarControl.TrackPosition + m_oScrollbarControl.PageSize )
					{
						//NativeMethods.SetCapture(Parent.SampleFramework.Window);
						m_bIsDragging = true;

						//Chris
						// If this is a double click, fire off an event and exit
						// since the first click would have taken care of the selection
						// updating.
						//if (msg == NativeMethods.WindowMessage.LeftButtonDoubleClick)
						//{
						//	RaiseDoubleClickEvent(this, true);
						//	return ;
						//}

						m_nSelectedIndex = clicked;
						//Chris
						//if ( (wParam.ToInt32() & ShiftModifier) == 0)
						//	m_nSelectedStarted = m_nSelectedIndex; // Shift isn't down

						// If this is a multi-selection listbox, update per-item
						// selection data.
						if (m_oStyle == ListBoxStyle.Multiselection)
						{
							// Determine behavior based on the oState of Shift and Ctrl
							ListBoxItem selectedItem = (ListBoxItem)m_oaItemList[m_nSelectedIndex];
							#region Not-Implimented Functionality
							//Chris
							/*if ((wParam.ToInt32() & (ShiftModifier | ControlModifier)) == ControlModifier)
								{
									// Control click, reverse the selection
									selectedItem.IsItemSelected = !selectedItem.IsItemSelected;
									m_oaItemList[m_nSelectedIndex] = selectedItem;
								}
								else if ((wParam.ToInt32() & (ShiftModifier | ControlModifier)) == ShiftModifier)
								{
									// Shift click. Set the selection for all items
									// from last selected item to the current item.
									// Clear everything else.
									int begin = Math.Min(m_nSelectedStarted, m_nSelectedIndex);
									int m_nEnd = Math.Max(m_nSelectedStarted, m_nSelectedIndex);
							
									// Unselect everthing before the beginning
									for(int i = 0; i < begin; ++i)
									{
										ListBoxItem lb = (ListBoxItem)m_oaItemList[i];
										lb.IsItemSelected = false;
										m_oaItemList[i] = lb;
									}
									// unselect everything after the m_nEnd
									for(int i = m_nEnd + 1; i < m_oaItemList.Count; ++i)
									{
										ListBoxItem lb = (ListBoxItem)m_oaItemList[i];
										lb.IsItemSelected = false;
										m_oaItemList[i] = lb;
									}
							
									// Select everything between
									for(int i = begin; i <= m_nEnd; ++i)
									{
										ListBoxItem lb = (ListBoxItem)m_oaItemList[i];
										lb.IsItemSelected = true;
										m_oaItemList[i] = lb;
									}
								}
								else if ((wParam.ToInt32() & (ShiftModifier | ControlModifier)) == (ShiftModifier | ControlModifier))
								{
									// Control-Shift-click.

									// The behavior is:
									//   Set all items from m_nSelectedStarted to m_nSelectedIndex to
									//     the same oState as m_nSelectedStarted, not including m_nSelectedIndex.
									//   Set m_nSelectedIndex to selected.
									int begin = Math.Min(m_nSelectedStarted, m_nSelectedIndex);
									int m_nEnd = Math.Max(m_nSelectedStarted, m_nSelectedIndex);

									// The two ends do not need to be set here.
									bool isLastSelected = ((ListBoxItem)m_oaItemList[m_nSelectedStarted]).IsItemSelected;

									for (int i = begin + 1; i < m_nEnd; ++i)
									{
										ListBoxItem lb = (ListBoxItem)m_oaItemList[i];
										lb.IsItemSelected = isLastSelected;
										m_oaItemList[i] = lb;
									}

									selectedItem.IsItemSelected = true;
									m_oaItemList[m_nSelectedIndex] = selectedItem;

									// Restore m_nSelectedIndex to the previous value
									// This matches the Windows behavior

									m_nSelectedIndex = m_nSelectedStarted;
								}
								else
								{
									// Simple click.  Clear all items and select the clicked
									// item.
									for(int i = 0; i < m_oaItemList.Count; ++i)
									{
										ListBoxItem lb = (ListBoxItem)m_oaItemList[i];
										lb.IsItemSelected = false;
										m_oaItemList[i] = lb;
									}
									selectedItem.IsItemSelected = true;
									m_oaItemList[m_nSelectedIndex] = selectedItem;
								}*/
							#endregion
						} // End of multi-selection case
						RaiseSelectionEvent(this, true);
					}
				}
				else
				{
					vScrollPos = new Vector2( vMousePosInControlSpace.X + this.Location.X - m_oScrollbarControl.Location.X,
											  vMousePosInControlSpace.Y + this.Location.Y - m_oScrollbarControl.Location.Y );
					bActionWasUsed = m_oScrollbarControl.OnMouseDown( vScrollPos,nButton );
				}
			}
		
			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				m_bIsDragging = false;

				if (m_nSelectedIndex != -1 && m_oaItemList.Count > 0 )
				{
					// Set all items between m_nSelectedStarted and m_nSelectedIndex to
					// the same oState as m_nSelectedStarted
					int m_nEnd = Math.Max(m_nSelectedStarted, m_nSelectedIndex);
					for (int i = Math.Min(m_nSelectedStarted, m_nSelectedIndex) + 1; i < m_nEnd; ++i)
					{
						ListBoxItem lb = (ListBoxItem)m_oaItemList[i];
						lb.IsItemSelected = ((ListBoxItem)m_oaItemList[m_nSelectedStarted]).IsItemSelected;
						m_oaItemList[i] = lb;
					}
					ListBoxItem lbs = (ListBoxItem)m_oaItemList[m_nSelectedIndex];
					lbs.IsItemSelected = ((ListBoxItem)m_oaItemList[m_nSelectedStarted]).IsItemSelected;
					m_oaItemList[m_nSelectedIndex] = lbs;

					// If m_nSelectedStarted and m_nSelectedIndex are not the same,
					// the user has dragged the mouse to make a selection.
					// Notify the application of this.
					if (m_nSelectedIndex != m_nSelectedStarted)
						RaiseSelectionEvent(this, true);
				}
			}
		
			return( bActionWasUsed );
		}

		public override bool OnMouseMove( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				if (m_bIsDragging)
				{
					// compute the index of the item below the cursor
					int itemIndex = -1;
					if (m_nTextHeight > 0)
						itemIndex = m_oScrollbarControl.TrackPosition + ( (int)( vMousePosInControlSpace.Y - (m_oTextRect.Y - base.m_vPos.Y) ) / m_nTextHeight );

					// Only proceed if the cursor is on top of an item
					if (itemIndex >= m_oScrollbarControl.TrackPosition &&
						itemIndex < m_oaItemList.Count &&
						itemIndex < m_oScrollbarControl.TrackPosition + m_oScrollbarControl.PageSize)
					{
						m_nSelectedIndex = itemIndex;
						RaiseSelectionEvent(this, true);
					}
					else if (itemIndex < m_oScrollbarControl.TrackPosition)
					{
						// User drags the mouse above window top
						m_oScrollbarControl.Scroll(-1);
						m_nSelectedIndex = m_oScrollbarControl.TrackPosition;
						RaiseSelectionEvent(this, true);
					}
					else if (itemIndex >= m_oScrollbarControl.TrackPosition + m_oScrollbarControl.PageSize)
					{
						// User drags the mouse below the window bottom
						m_oScrollbarControl.Scroll(1);
						m_nSelectedIndex = Math.Min(m_oaItemList.Count, m_oScrollbarControl.TrackPosition + m_oScrollbarControl.PageSize - 1);
						RaiseSelectionEvent(this, true);
					}
				}
			}
		
			return( bActionWasUsed );
		}


        
		#region Item Controlling methods
		/// <summary>Adds an item to the list box control</summary>
		public int AddItem(string text, object data)
		{
			int nIndex = -1;

			if ((text == null) || (text.Length == 0))
				throw new ArgumentNullException("text", "You must pass in a valid item name when adding a new item.");

			// Create a new item and add it
			ListBoxItem newitem = new ListBoxItem();
			newitem.ItemText = text;
			newitem.ItemData = data;
			newitem.IsItemSelected = false;
			nIndex = m_oaItemList.Add(newitem);

			// Update the scrollbar with the new range
			m_oScrollbarControl.SetTrackRange(0, m_oaItemList.Count);

			return( nIndex );
		}
		/// <summary>Inserts an item to the list box control</summary>
		public void InsertItem(int index, string text, object data)
		{
			if ((text == null) || (text.Length == 0))
				throw new ArgumentNullException("text", "You must pass in a valid item name when adding a new item.");

			// Create a new item and insert it
			ListBoxItem newitem = new ListBoxItem();
			newitem.ItemText = text;
			newitem.ItemData = data;
			newitem.IsItemSelected = false;
			m_oaItemList.Insert(index, newitem);

			// Update the scrollbar with the new range
			m_oScrollbarControl.SetTrackRange(0, m_oaItemList.Count);
		}

		/// <summary>Removes an item at a particular index</summary>
		public void RemoveAt(int index)
		{
			// Remove the item
			m_oaItemList.RemoveAt(index);

			// Update the scrollbar with the new range
			m_oScrollbarControl.SetTrackRange(0, m_oaItemList.Count);

			if (m_nSelectedIndex >= m_oaItemList.Count)
				m_nSelectedIndex = m_oaItemList.Count - 1;

			RaiseSelectionEvent(this, true);
		}
		public void Remove( string sValue )
		{
			int nIndex = GetItemIndex( sValue );

			if( nIndex > -1 )
			{
				RemoveAt( nIndex );
			}
		}
		private int GetItemIndex( string sValue )
		{
			ListBoxItem oItem;
			int nIndex = -1;

			for( int i=0 ; i<m_oaItemList.Count ; i++ )
			{
				oItem = (ListBoxItem)m_oaItemList[ i ];
				if( oItem.ItemText == sValue )
				{
					nIndex = i;
					break;
				}
			}

			return( nIndex );
		}
		private int GetItemIndex( object oValue )
		{
			ListBoxItem oItem;
			int nIndex = -1;

			for( int i=0 ; i<m_oaItemList.Count ; i++ )
			{
				oItem = (ListBoxItem)m_oaItemList[ i ];
				if( oItem.ItemData.Equals( oValue ) == true )
				{
					nIndex = i;
					break;
				}
			}

			return( nIndex );
		}


		/// <summary>Removes all items from the control</summary>
		public void Clear()
		{
			// clear the list
			m_oaItemList.Clear();

			// Update scroll bar and index
			m_oScrollbarControl.SetTrackRange(0, 1);
			m_nSelectedIndex = -1;
		}

		/// <summary>
		/// For single-selection listbox, returns the index of the selected item.
		/// For multi-selection, returns the first selected item after the previousSelected m_nPosition.
		/// To search for the first selected item, the app passes -1 for previousSelected.  For
		/// subsequent searches, the app passes the returned index back to GetSelectedIndex as.
		/// previousSelected.
		/// Returns -1 on error or if no item is selected.
		/// </summary>
		public int GetSelectedIndex()
		{
			return( GetSelectedIndex( -1 ) ); 
		}
		public int GetSelectedIndex(int previousSelected)
		{
			if (previousSelected < -1)
				return -1;

			if (m_oStyle == ListBoxStyle.Multiselection)
			{
				// Multiple selections m_bEnabled.  Search for the next item with the selected flag
				for (int i = previousSelected + 1; i < m_oaItemList.Count; ++i)
				{
					ListBoxItem lbi = (ListBoxItem)m_oaItemList[i];
					if (lbi.IsItemSelected)
						return i;
				}

				return -1;
			}
			else
			{
				// Single selection
				return m_nSelectedIndex;
			}
		}
		public ListBoxItem GetByIndex( int nIndex )
		{
			return (ListBoxItem)m_oaItemList[nIndex];
		}
		/// <summary>Gets the selected item</summary>
		public ListBoxItem GetSelectedItem(int previousSelected)
		{
			return (ListBoxItem)m_oaItemList[GetSelectedIndex(previousSelected)];
		}
		/// <summary>Gets the selected item</summary>
		public ListBoxItem GetSelectedItem() { return GetSelectedItem(-1); }

		/// <summary>Sets the m_nBorder and m_nMargin sizes</summary>
		public void SetBorder(int borderSize, int marginSize)
		{
			m_nBorder = borderSize;
			m_nMargin = marginSize;
			OnResize();
		}

		/// <summary>Selects this item</summary>
		public void SelectItem(int newIndex)
		{
			if (m_oaItemList.Count == 0)
				return; // If no items exist there's nothing to do

			int oldSelected = m_nSelectedIndex;

			// Select the new item
			m_nSelectedIndex = newIndex;

			// Clamp the item
			if (m_nSelectedIndex < 0)
				m_nSelectedIndex = 0;
			if (m_nSelectedIndex > m_oaItemList.Count)
				m_nSelectedIndex = m_oaItemList.Count - 1;

			// Did the selection change?
			if (oldSelected != m_nSelectedIndex)
			{
				if (m_oStyle == ListBoxStyle.Multiselection)
				{
					ListBoxItem lbi = (ListBoxItem)m_oaItemList[m_nSelectedIndex];
					lbi.IsItemSelected = true;
					m_oaItemList[m_nSelectedIndex] = lbi;
				}

				// Update selection m_nStart
				m_nSelectedStarted = m_nSelectedIndex;

				// adjust scrollbar
				m_oScrollbarControl.ShowItem(m_nSelectedIndex);
			}
			RaiseSelectionEvent(this, true);
		}

		public int GetItemCount()
		{
			return( m_oaItemList.Count );
		}
		#endregion


		#region Properties
		public override bool CanHaveFocus { get { return (Visible && Enabled); } }
		public ListBoxStyle Style { get { return m_oStyle; } set { m_oStyle = value; } } 
		public int NumberItems { get { return m_oaItemList.Count; } }
		public ListBoxItem this[int index]
		{
			get { return (ListBoxItem)m_oaItemList[index]; }
		}

		public int ScrollbarWidth
		{
			set
			{
				m_nScrollWidth = value;
				OnResize();
			}
			get
			{
				return( m_nScrollWidth );
			}
		}
		public override DSGraphicsWrapper DSGraphicsWrapper
		{
			get
			{
				return( base.DSGraphicsWrapper );
			}
			set
			{
				base.DSGraphicsWrapper = value;
				m_oScrollbarControl.DSGraphicsWrapper = value;
			}
		}
		public override DSForm Form
		{
			get
			{
				return( m_oForm );
			}
			set
			{
				m_oScrollbarControl.Form = value;
				m_oForm = value;
			}
		}
		public override System.Drawing.Color FontColor
		{
			get
			{
				return( base.FontColor );
			}
			set
			{
				base.FontColor = value;
				Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );

				m_oMainLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
				m_oSelectionLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;

				m_oMainLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
				m_oSelectionLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
			}
		}
		#endregion
	}

	#endregion

	#region EditBox Control
	public class DSEditBox : DSBaseControl
	{
		#region Properties
		protected BlendColor m_oMainLayer_FontColor;
		protected DrawTextFormat m_oTextFormat = DrawTextFormat.Left | DrawTextFormat.Top;

		protected BlendColor[] m_oTextureState = new BlendColor[ 9 ];
		protected System.Drawing.Rectangle[] m_oTextureRect = new System.Drawing.Rectangle[ 9 ]; // Bounding rectangle of this element on the composite texture

		protected DSThreadSafeRichTextBox m_oTextData = null;
		protected int m_nBorder = 5; // Border of the window
		protected int m_nSpacing = 4; // Spacing between the text and the edge of m_nBorder
		protected System.Drawing.Rectangle m_oTextRect; // Bounding rectangle for the text
		protected System.Drawing.Rectangle[] m_oaElementRects = new System.Drawing.Rectangle[ 9 ];
		protected double m_dBlinkTime = .53f; // Caret blink time in milliseconds
		protected double m_dLastBlink = 0; // Last timestamp of caret blink
		protected bool m_bIsCaretOn = true; // Flag to indicate whether caret is currently m_bVisible
		protected int m_nCaretPosition = 0; // Caret m_nPosition, in characters
		protected bool m_bIsInsertMode = true; // If true, control is in insert mode. Else, overwrite mode.
		protected int m_nFirstVisible = 0;  // First m_bVisible character in the edit control
		protected ColorValue m_oTextColor = new ColorValue(0.06f, 0.06f, 0.06f, 1.0f); // Text color
		protected ColorValue m_oSelectedTextColor = new ColorValue(1.0f, 1.0f, 1.0f, 1.0f); // Selected Text color
		protected ColorValue m_oSelectedBackColor = new ColorValue(0.15f, 0.196f, 0.36f, 1.0f); // Selected background color
		protected ColorValue m_oCaretColor = Microsoft.DirectX.Direct3D.ColorValue.FromColor( System.Drawing.Color.Black ); // Caret color

		protected bool m_bIsMouseDragging = false; // True to indicate the drag is in progress

		protected static bool m_bIsHidingCaret = false; // If true, we don't render the caret.

		#region Element layers
		public const int TextLayer = 0;
		public const int TopLeftBorder = 1;
		public const int TopBorder = 2;
		public const int TopRightBorder = 3;
		public const int LeftBorder = 4;
		public const int RightBorder = 5;
		public const int LowerLeftBorder = 6;
		public const int LowerBorder = 7;
		public const int LowerRightBorder = 8;
		#endregion

		#region Event code
		public event EventHandler Changed;
		public event EventHandler Enter;
		public event EventHandler Esc;
		/// <summary>Raises the changed event</summary>
		protected void RaiseChangedEvent(DSEditBox sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			// m_bEnabled
			if ( !wasTriggeredByUser)
				return;

			if (Changed != null)
				Changed(sender, EventArgs.Empty);
		}
		/// <summary>Raises the Enter event</summary>
		protected void RaiseEnterEvent(DSEditBox sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			if ( !wasTriggeredByUser)
				return;

			if (Enter != null)
				Enter(sender, EventArgs.Empty);
		}
		protected void RaiseEscEvent(DSEditBox sender, bool wasTriggeredByUser)
		{
			// Discard events triggered programatically if these types of events haven't been
			if ( !wasTriggeredByUser)
				return;

			if (Esc != null)
				Esc(sender, EventArgs.Empty);
		}
		#endregion
		#endregion


		public DSEditBox( DSForms oForms,DSForm oForm ) : base( oForms,oForm )
		{
			Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );

			CreateRTFControl();


			m_oTextureState[ TextLayer ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ TextLayer ] = new System.Drawing.Rectangle(14,90,227,23);

			m_oTextureState[ TopLeftBorder ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ TopLeftBorder ] = new System.Drawing.Rectangle(8,82,6,8);

			m_oTextureState[ TopBorder ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ TopBorder ] = new System.Drawing.Rectangle(14,82,227,8);

			m_oTextureState[ TopRightBorder ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ TopRightBorder ] = new System.Drawing.Rectangle(241,82,5,8);

			m_oTextureState[ LeftBorder ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ LeftBorder ] = new System.Drawing.Rectangle(8,90,6,23);

			m_oTextureState[ RightBorder ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ RightBorder ] = new System.Drawing.Rectangle(241,90,5,23);

			m_oTextureState[ LowerLeftBorder ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ LowerLeftBorder ] = new System.Drawing.Rectangle(8,113,6,8);

			m_oTextureState[ LowerBorder ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ LowerBorder ] = new System.Drawing.Rectangle(14,113,227,8);

			m_oTextureState[ LowerRightBorder ].Initialize( DSForm.WhiteColorValue );
			m_oTextureRect[ LowerRightBorder ] = new System.Drawing.Rectangle(241,113,5,8);

			m_oMainLayer_FontColor.Initialize( oFontColor );


			m_oMainLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
			m_oMainLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
		}
		private void CreateRTFControl()
		{
			m_oTextData = new DSThreadSafeRichTextBox();

			//m_oTextData.Visible = true;
			//m_oTextData.Font = new System.Drawing.Font("Arial", 8.0f);
			//m_oTextData.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
			//m_oTextData.Multiline = false;
			m_oTextData.Text = string.Empty;
			m_oTextData.MaxLength = ushort.MaxValue; // 65k characters should be plenty
			m_oTextData.Font = base.Font;
			//m_oTextData.WordWrap = false;
			m_oTextData.SelectionStart = 0;
		}


		public override string Serialize()
		{
			string sRetVal = "";

			sRetVal = base.Serialize() + m_cSEP +  
					  m_oTextData.Text + m_cSEP + 
					  m_nBorder.ToString() + m_cSEP + 
					  m_nSpacing.ToString() + m_cSEP + 
					  m_dBlinkTime.ToString() + m_cSEP + 
					  m_dLastBlink.ToString() + m_cSEP + 
					  m_bIsCaretOn.ToString() + m_cSEP + 
					  m_nCaretPosition.ToString() + m_cSEP + 
					  m_bIsInsertMode.ToString() + m_cSEP + 
					  m_nFirstVisible.ToString() + m_cSEP + 
					  m_oTextData.SelectionStart.ToString();

			return( sRetVal );
		}
		public override string DeSerialize( string sRecord )
		{
			string sRemainder = "";
			string sRecordLeft = "";
			string[] saParsed = null;


			sRecordLeft = base.DeSerialize( sRecord );
			saParsed = DSMisc.Split( sRecordLeft,m_cSEP );

			m_oTextData.Text = saParsed[ 0 ];
			m_nBorder = Convert.ToInt32( saParsed[ 1 ] );
			m_nSpacing = Convert.ToInt32( saParsed[ 2 ] );
			m_dBlinkTime = Convert.ToDouble( saParsed[ 3 ] );
			//m_dLastBlink = Convert.ToDouble( saParsed[ 4 ] );
			m_bIsCaretOn = Convert.ToBoolean( saParsed[ 5 ] );
			m_nCaretPosition = Convert.ToInt32( saParsed[ 6 ] );
			m_bIsInsertMode = Convert.ToBoolean( saParsed[ 7 ] );
			m_nFirstVisible = Convert.ToInt32( saParsed[ 8 ] );
			m_oTextData.SelectionStart = Convert.ToInt32( saParsed[ 9 ] );

			OnResize();

			for( int i=10 ; i<saParsed.Length ; i++ )
			{
				sRemainder += saParsed[ i ];

				if( i<saParsed.Length-1 )
				{
					sRemainder += m_cSEP;
				}
			}


			return( sRemainder );
		}

		
		protected void PlaceCaret(int pos)
		{
			try
			{
				// Store caret m_nPosition
				m_nCaretPosition = pos;

				// First find the first m_bVisible char
				for (int i = 0; i < m_oTextData.Text.Length; i++)
				{
					System.Drawing.Point p = m_oTextData.GetPositionFromCharIndex(i);
					if (p.X >= 0) 
					{
						m_nFirstVisible = i; // This is the first m_bVisible character
						break;
					}
				}

				//If the new m_nPosition is smaller than the first m_bVisible char we'll need to scroll
				if (m_nFirstVisible > m_nCaretPosition)
				{
					m_nFirstVisible = m_nCaretPosition;
				}
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}
		}

		public void Clear()
		{
			m_oTextData.Text = string.Empty;
			PlaceCaret(0);
			m_oTextData.SelectionStart = 0;
		}
		public void SetText(string text, bool selected)
		{
			if (text == null)
				text = string.Empty;

			m_oTextData.Text = text;

			//This control appears to be thread vulnerable.  We check here to see if it was 
			//created in a different thread and if it was then we recreate it now.
/*			if( m_oTextData.Text != text )
			{
				CreateRTFControl();
				m_oTextData.Text = text;
			}*/

			m_oTextData.SelectionStart = text.Length;
			// Move the care to the End of the text
			PlaceCaret(text.Length);
			m_oTextData.SelectionStart = (selected) ? 0 : m_nCaretPosition;
		}
		protected void DeleteSelectionText()
		{
			int first = Math.Min(m_nCaretPosition, m_oTextData.SelectionStart);
			int last = Math.Max(m_nCaretPosition, m_oTextData.SelectionStart);

			// Update caret and selection
			PlaceCaret(first);

			// Remove the characters
			m_oTextData.Text = m_oTextData.Text.Remove(first, (last-first));
			m_oTextData.SelectionStart = m_nCaretPosition;
		}
		public override void OnResize()
		{
			// Update text rect
			Rectangle boundingBox = new Rectangle( (int)this.Location.X,(int)this.Location.Y,(int)this.Size.X,(int)this.Size.Y );
			m_oTextRect = boundingBox;
			// First inflate by m_nBorder to compute render rects
			m_oTextRect.Inflate(-m_nBorder, -m_nBorder);
            
			// Update the render rectangles
			m_oaElementRects[0] = m_oTextRect;
			m_oaElementRects[1] = new System.Drawing.Rectangle(boundingBox.Left, boundingBox.Top, (m_oTextRect.Left - boundingBox.Left), (m_oTextRect.Top - boundingBox.Top));
			m_oaElementRects[2] = new System.Drawing.Rectangle(m_oTextRect.Left, boundingBox.Top, m_oTextRect.Width, (m_oTextRect.Top - boundingBox.Top));
			m_oaElementRects[3] = new System.Drawing.Rectangle(m_oTextRect.Right, boundingBox.Top, (boundingBox.Right - m_oTextRect.Right), (m_oTextRect.Top - boundingBox.Top));
			m_oaElementRects[4] = new System.Drawing.Rectangle(boundingBox.Left, m_oTextRect.Top, (m_oTextRect.Left - boundingBox.Left), m_oTextRect.Height);
			m_oaElementRects[5] = new System.Drawing.Rectangle(m_oTextRect.Right, m_oTextRect.Top, (boundingBox.Right - m_oTextRect.Right), m_oTextRect.Height);
			m_oaElementRects[6] = new System.Drawing.Rectangle(boundingBox.Left, m_oTextRect.Bottom, (m_oTextRect.Left - boundingBox.Left), (boundingBox.Bottom - m_oTextRect.Bottom));
			m_oaElementRects[7] = new System.Drawing.Rectangle(m_oTextRect.Left, m_oTextRect.Bottom, m_oTextRect.Width, (boundingBox.Bottom - m_oTextRect.Bottom));
			m_oaElementRects[8] = new System.Drawing.Rectangle(m_oTextRect.Right, m_oTextRect.Bottom, (boundingBox.Right - m_oTextRect.Right), (boundingBox.Bottom - m_oTextRect.Bottom));            

			// Inflate further by m_nSpacing
			m_oTextRect.Inflate(-m_nSpacing, -m_nSpacing);

			// Make the underlying rich text box the same size
			//m_oTextData.Size = m_oTextRect.Size;
		}

		protected void CopyToClipboard()
		{
			// Copy the selection text to the clipboard
			if (m_nCaretPosition != m_oTextData.SelectionStart)
			{
				int first = Math.Min(m_nCaretPosition, m_oTextData.SelectionStart);
				int last = Math.Max(m_nCaretPosition, m_oTextData.SelectionStart);
				// Set the text to the clipboard
				System.Windows.Forms.Clipboard.SetDataObject(m_oTextData.Text.Substring(first, (last-first)));
			}

		}
		protected void PasteFromClipboard()
		{
			// Get the clipboard data
			System.Windows.Forms.IDataObject clipData = System.Windows.Forms.Clipboard.GetDataObject();
			// Does the clipboard have string data?
			if (clipData.GetDataPresent(System.Windows.Forms.DataFormats.StringFormat))
			{
				// Yes, get that data
				string clipString = clipData.GetData(System.Windows.Forms.DataFormats.StringFormat) as string;
				// find any new lines, remove everything after that
				int index;
				if ((index = clipString.IndexOf("\n")) > 0)
				{
					clipString = clipString.Substring(0, index-1);
				}

				// Insert that into the text data
				m_oTextData.Text = m_oTextData.Text.Insert(m_nCaretPosition, clipString);
				m_nCaretPosition += clipString.Length;
				m_oTextData.SelectionStart = m_nCaretPosition;
			}
		}
		protected void ResetCaretBlink()
		{
			m_bIsCaretOn = true;
			m_dLastBlink = base.m_dAppTime;
		}

		public override void OnFocusIn()
		{
			base.OnFocusIn();
			ResetCaretBlink();
		}


		public override bool OnKeyDown( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;
			bool bAddOne = false;
			string sTemp = "";


			if( Enabled == true && Visible == true )
			{
				if( 
					(
						oKey == Microsoft.DirectX.DirectInput.Key.End ||
						oKey == Microsoft.DirectX.DirectInput.Key.Home 
					)
					||
					(
						this.m_oForms.DSInputWrapper.NumLockToggled == false &&
						(
							oKey == Microsoft.DirectX.DirectInput.Key.NumPad1 ||
							oKey == Microsoft.DirectX.DirectInput.Key.NumPad7
						)
					)
				  )
				{
					// Move the caret
					if( oKey == Microsoft.DirectX.DirectInput.Key.End ||
						oKey == Microsoft.DirectX.DirectInput.Key.NumPad1 )
					{
						PlaceCaret(m_oTextData.Text.Length);
					}
					else
					{
						PlaceCaret(0);
					}
					if( oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftShift ] == false &&
						oState[ (int)Microsoft.DirectX.DirectInput.Key.RightShift ] == false )
					{
						// Shift is not down. Update selection m_nStart along with caret
						m_oTextData.SelectionStart = m_nCaretPosition;
					}

					ResetCaretBlink();
					bActionWasUsed = true;
				}
				//Paste
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Insert ||
						 (
							oKey == Microsoft.DirectX.DirectInput.Key.V &&
							(
								oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftControl ] == true ||
								oState[ (int)Microsoft.DirectX.DirectInput.Key.RightControl ] == true
							)
						 )
					   )
				{
					if( oKey == Microsoft.DirectX.DirectInput.Key.V ||
						(
							oKey == Microsoft.DirectX.DirectInput.Key.Insert &&
							(
								oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftShift ] == true ||
								oState[ (int)Microsoft.DirectX.DirectInput.Key.RightShift ] == true 
							)
						)
					   )
					{
						// Shift insert -> Paste from clipboard
						DeleteSelectionText();
						PasteFromClipboard();
						RaiseChangedEvent(this, true);
					}
					else
					{
						// Toggle insert mode
						m_bIsInsertMode = !m_bIsInsertMode;
					}
				}
				//Copy
				else if( oKey == Microsoft.DirectX.DirectInput.Key.C &&
						 (
							oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftControl ] == true ||
							oState[ (int)Microsoft.DirectX.DirectInput.Key.RightControl ] == true
						 )
					   ) 
				{
					// Control insert -> Copy to clipboard
					CopyToClipboard();
				}
				//Cut
				else if( 
						 (
							oKey == Microsoft.DirectX.DirectInput.Key.Delete &&
							(
								oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftShift ] == true ||
								oState[ (int)Microsoft.DirectX.DirectInput.Key.RightShift ] == true 
							)
						 )		
						 ||
						 (
							oKey == Microsoft.DirectX.DirectInput.Key.X &&
							(
								oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftControl ] == true ||
								oState[ (int)Microsoft.DirectX.DirectInput.Key.RightControl ] == true
							)
						 )
					   )
				{
					CopyToClipboard();
					DeleteSelectionText();
					RaiseChangedEvent(this, true);
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Delete ||
						 (
							oKey == Microsoft.DirectX.DirectInput.Key.NumPadPeriod &&
							m_oForms.DSInputWrapper.NumLockToggled == false
						 )
					   )
				{
					// Check to see if there is a text selection
					if (m_nCaretPosition != m_oTextData.SelectionStart)
					{
						DeleteSelectionText();
						RaiseChangedEvent(this, true);
					}
					else
					{
						if (m_nCaretPosition < m_oTextData.Text.Length)
						{
							// Deleting one character
							m_oTextData.Text = m_oTextData.Text.Remove(m_nCaretPosition, 1);
							RaiseChangedEvent(this, true);
						}
						m_oTextData.SelectionStart = m_nCaretPosition;
					}
					ResetCaretBlink();
					bActionWasUsed = true;
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Left || 
						 (
							oKey == Microsoft.DirectX.DirectInput.Key.NumPad4 &&
							m_oForms.DSInputWrapper.NumLockToggled == false
						 )
					   )
				{
					if( oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftControl ] == true ||
						oState[ (int)Microsoft.DirectX.DirectInput.Key.RightControl ] == true )
					{
						// Control is down. Move the caret to a new item instead of a character.
					}
					else if (m_nCaretPosition > 0)
					{
						PlaceCaret(m_nCaretPosition - 1); // Move one to the left
					}

					if( oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftShift ] == false &&
						oState[ (int)Microsoft.DirectX.DirectInput.Key.RightShift ] == false )
					{
						// Shift is not down. Update selection
						// m_nStart along with the caret.
						m_oTextData.SelectionStart = m_nCaretPosition;
					}
					ResetCaretBlink();
					bActionWasUsed = true;
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Right || 
						 (
							oKey == Microsoft.DirectX.DirectInput.Key.NumPad6 &&
							m_oForms.DSInputWrapper.NumLockToggled == false
						 )
					   )
				{
					if( oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftControl ] == true ||
						oState[ (int)Microsoft.DirectX.DirectInput.Key.RightControl ] == true )
					{
						// Control is down. Move the caret to a new item
						// instead of a character.
					}
					else if (m_nCaretPosition < m_oTextData.Text.Length)
					{
						PlaceCaret(m_nCaretPosition + 1); // Move one to the left
					}
					if( oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftShift ] == false &&
						oState[ (int)Microsoft.DirectX.DirectInput.Key.RightShift ] == false )
					{
						// Shift is not down. Update selection
						// m_nStart along with the caret.
						m_oTextData.SelectionStart = m_nCaretPosition;
					}
					ResetCaretBlink();
					bActionWasUsed = true;
				}
				else if( oKey == Microsoft.DirectX.DirectInput.Key.Up ||
						 oKey == Microsoft.DirectX.DirectInput.Key.Down )
				{
					// Trap up and down arrows so that the dialog  does not switch focus to another control.
					bActionWasUsed = true;
				}
				else if( oKey != Microsoft.DirectX.DirectInput.Key.LeftControl &&
						 oKey != Microsoft.DirectX.DirectInput.Key.RightControl )
				{				
					// Let the application handle escape
					//bActionWasUsed = ((System.Windows.Forms.Keys)wParam.ToInt32()) == System.Windows.Forms.Keys.Escape;

					if( oKey == Microsoft.DirectX.DirectInput.Key.Back )
					{
						// If there's a selection, treat this like a delete key.
						if (m_nCaretPosition != m_oTextData.SelectionStart)
						{
							DeleteSelectionText();
							RaiseChangedEvent(this, true);
						}
						else if (m_nCaretPosition > 0)
						{
							// Move the caret and delete the char
							m_oTextData.Text = m_oTextData.Text.Remove(m_nCaretPosition - 1, 1);
							PlaceCaret(m_nCaretPosition - 1);
							m_oTextData.SelectionStart = m_nCaretPosition;
							RaiseChangedEvent(this, true);
						}

						ResetCaretBlink();
						bActionWasUsed = true;
					}
					else if( oKey == Microsoft.DirectX.DirectInput.Key.Return ||
							 oKey == Microsoft.DirectX.DirectInput.Key.NumPadEnter )
					{						
						// Invoke the event when the user presses Enter.
						RaiseEnterEvent(this, true);
						bActionWasUsed = true;
					}
					else if( oKey == Microsoft.DirectX.DirectInput.Key.Escape )
					{
						// Invoke the event when the user presses Enter.
						RaiseEscEvent(this, true);
						bActionWasUsed = true;
					}
					// Ctrl-A Select All
					else if( oKey == Microsoft.DirectX.DirectInput.Key.A &&
							 (
								oState[ (int)Microsoft.DirectX.DirectInput.Key.LeftControl ] == true ||
								oState[ (int)Microsoft.DirectX.DirectInput.Key.RightControl ] == true 
							 )
						   )
					{
						m_oTextData.SelectionStart = 0;
						PlaceCaret( m_oTextData.Text.Length );
					}
					else
					{
						sTemp = DSMisc.KeyToChar( oKey,oState,
										this.m_oForms.DSInputWrapper.CapsLockToggled,
										this.m_oForms.DSInputWrapper.NumLockToggled );

						// If there's a selection and the user starts to type, the selection should be deleted.
						if( sTemp.Length > 0 && 
							m_nCaretPosition != m_oTextData.SelectionStart )
						{
							DeleteSelectionText();
						}
						// If we are in overwrite mode and there is already a char at the caret's m_nPosition, simply replace it.
						// Otherwise, we insert the char as normal.
						if (!m_bIsInsertMode && m_nCaretPosition < m_oTextData.Text.Length)
						{
							// This isn't the most efficient way to do this, but it's simple
							// and shows the correct behavior
							char[] charData = m_oTextData.Text.ToCharArray();
							charData[m_nCaretPosition] = Convert.ToChar( sTemp );
							m_oTextData.Text = new string(charData);
							bAddOne = true;
						}
						else
						{
							// Insert the char
							if( sTemp.Length > 0 )
							{
								bAddOne = true;
								m_oTextData.Text = m_oTextData.Text.Insert( m_nCaretPosition,sTemp );
							}
						}

						// Move the caret and selection m_nPosition now
						if( bAddOne == true )
						{
							PlaceCaret(m_nCaretPosition + 1);
							m_oTextData.SelectionStart = m_nCaretPosition;

							ResetCaretBlink();
							RaiseChangedEvent(this, true);
							bActionWasUsed = true;
						}
					}
				}


				RaiseKeyDownEvent( this,oKey,oState );
			}
		
			return( bActionWasUsed );
		}

		public override bool OnKeyUp( Key oKey,bool[] oState )
		{
			bool bActionWasUsed = false;

			bActionWasUsed = (m_oForm.ControlWithFocus == this );

			return( bActionWasUsed );
		}

		public override bool OnMouseMove( Vector2 vMousePosInControlSpace,bool[] baButtons )
		{
			bool bActionWasUsed = false;
			System.Drawing.Point oEndPoint;


			if( Enabled == true && Visible == true )
			{
				if (m_bIsMouseDragging)
				{
					// We need a new point
					System.Drawing.Point p = new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y );
					p.X -= ( m_oTextRect.Left - this.Location.X );
					p.Y = 1;//-= ( m_oTextRect.Top - this.Location.Y );

					// Determine the character corresponding to the coordinates
					int dragIndex = m_oTextData.GetCharIndexFromPosition( p );
					oEndPoint = m_oTextData.GetPositionFromCharIndex( m_oTextData.Text.Length + 1 );

					if( p.X > oEndPoint.X && dragIndex + 1 <= m_oTextData.Text.Length )
					{
						PlaceCaret( dragIndex + 1 );
					}
					else
					{
						PlaceCaret( dragIndex );
					}						
				}
			}
		
			return( bActionWasUsed );
		}
		public override bool OnMouseUp( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;
			m_bIsMouseDragging = false;
			return( bActionWasUsed );
		}
		public override bool OnMouseDown( Vector2 vMousePosInControlSpace,long nButton )
		{
			bool bActionWasUsed = false;

			if( Enabled == true && Visible == true )
			{
				// We need a new point
				System.Drawing.Point p = new Point((int)vMousePosInControlSpace.X,(int)vMousePosInControlSpace.Y );
				p.X -= ( m_oTextRect.Left - this.Location.X );
				p.Y -= ( m_oTextRect.Top - this.Location.Y );

				// Get focus first
				//if (! m_oForm.ControlWithFocus == this )
				//	DSForm.RequestFocus(this);

				if( ContainsPoint( new Point((int)( vMousePosInControlSpace.X + this.Location.X ),
											 (int)( vMousePosInControlSpace.Y + this.Location.Y ) ) ) == true )
				{
					m_bIsMouseDragging = true;
					//NativeMethods.SetCapture(Parent.SampleFramework.Window);
					// Determine the character corresponding to the coordinates
					//If we are doing this we want to make sure the Y fits so adjust it
					p.Y = m_oTextRect.Top - this.Location.Y - 1;
					int index = m_oTextData.GetCharIndexFromPosition(p);

					System.Drawing.Point startPosition = m_oTextData.GetPositionFromCharIndex(index);

					if (p.X > startPosition.X && index < m_oTextData.Text.Length)
						PlaceCaret(index + 1);
					else
						PlaceCaret(index);
                    
					m_oTextData.SelectionStart = m_nCaretPosition;
					ResetCaretBlink();
				}
			}
		
			return( bActionWasUsed );
		}


		public override void Render()
		{
			string sTemp = "";
			System.Drawing.Rectangle oCursor;


			if (!Visible)
				return; // Nothing to render

			base.Render();

			// Render the control graphics
			for (int i = 0; i <= LowerRightBorder; ++i)
			{
				//Element e = elementList[i] as Element;
				m_oTextureState[ i ].Blend(ControlState.Normal,m_dElapsedTime);
				m_oForm.RenderTexture2D( m_cFORMTEXTUREKEY,m_oaElementRects[i],m_oTextureState[ i ].Current.ToArgb(),m_oTextureRect[ i ] );
			}

			// Compute the X coordinates of the first m_bVisible character.
			int xFirst = m_oTextData.GetPositionFromCharIndex(m_nFirstVisible).X;
			int xCaret = m_oTextData.GetPositionFromCharIndex(m_nCaretPosition).X;
			int xSel;

			if (m_nCaretPosition != m_oTextData.SelectionStart)
				xSel = m_oTextData.GetPositionFromCharIndex(m_oTextData.SelectionStart).X;
			else
				xSel = xCaret;

			// Render the selection rectangle
			System.Drawing.Rectangle selRect = System.Drawing.Rectangle.Empty;
			if (m_nCaretPosition != m_oTextData.SelectionStart)
			{
				int selLeft = xCaret, selRight = xSel;
				// Swap if left is beigger than right
				if (selLeft > selRight)
				{
					int temp = selLeft;
					selLeft = selRight;
					selRight = temp;
				}
				selRect = System.Drawing.Rectangle.FromLTRB( selLeft, m_oTextRect.Top, selRight, m_oTextRect.Bottom );
				selRect.Offset(m_oTextRect.Left - xFirst, 0);
				selRect.Intersect(m_oTextRect);

				//Offset for the form location
				//selRect.Offset( (int)m_oForm.Location.X,(int)m_oForm.Location.Y );

				m_oForm.RenderRect2D(selRect, m_oSelectedBackColor.ToArgb() );
			}

			// Render the text
			m_oMainLayer_FontColor.Current = m_oTextColor;
			sTemp = m_oTextData.Text;
			sTemp = sTemp.Substring( m_nFirstVisible );
			m_oForm.RenderText( base.Font,sTemp, m_oTextRect,m_oMainLayer_FontColor,m_oTextFormat );

			// Render the selected text
			if (m_nCaretPosition != m_oTextData.SelectionStart)
			{
				int firstToRender = Math.Max(m_nFirstVisible, Math.Min(m_oTextData.SelectionStart, m_nCaretPosition));
				int numToRender = Math.Max(m_oTextData.SelectionStart, m_nCaretPosition) - firstToRender;
				m_oMainLayer_FontColor.Current = m_oSelectedTextColor;

				sTemp = m_oTextData.Text;
				if( firstToRender < sTemp.Length )
				{
					sTemp = sTemp.Substring( firstToRender, numToRender );
				}
				m_oForm.RenderText( base.Font,sTemp,selRect,m_oMainLayer_FontColor,m_oTextFormat );
			}

			//Blink the caret
			if( base.m_dAppTime - m_dLastBlink >= m_dBlinkTime )
			{
				m_bIsCaretOn = !m_bIsCaretOn;
				m_dLastBlink = base.m_dAppTime;
			}


			// Render the caret if this control has the focus and were enabled
			if( m_oForms.FormWithFocus == m_oForm && m_oForm.ControlWithFocus == this && 
				m_bIsCaretOn && !m_bIsHidingCaret && base.Enabled == true )
			{
				// Start the rectangle with insert mode caret
				System.Drawing.Rectangle caretRect = m_oTextRect;
				caretRect.Width = 2;
				caretRect.Location = new System.Drawing.Point(caretRect.Left - xFirst + xCaret -1, caretRect.Top);
                
				// If we are in overwrite mode, adjust the caret rectangle to fill the entire character.
				if (!m_bIsInsertMode)
				{
					// Obtain the X coord of the current character
					caretRect.Width = 4;
				}


				// Draw a wrapper to designate which control we are looking at
				oCursor = caretRect;
				oCursor.Offset( (int)this.Form.Location.X,(int)this.Form.Location.Y );
				this.DSGraphicsWrapper.RenderTexture2D( "System_NoTexture",new System.Drawing.Rectangle(0,0,1,1),oCursor,
														new Vector2(0,0),0,0,false,System.Drawing.Color.Black.ToArgb() );
			}
		}



		#region Properties
		public int SetSpacing
		{ 
			set
			{
				m_nSpacing = value; 
				OnResize(); 
			}
		}
		public int SetBorderWidth
		{ 
			set
			{
				m_nBorder = value;
				OnResize(); 		
			}
		}
		public ColorValue SetTextColor
		{ 
			set
			{
				this.FontColor = System.Drawing.Color.FromArgb( value.ToArgb() );
			}
		}
		public ColorValue SetSelectedTextColor
		{ 
			set
			{
				m_oSelectedTextColor = value; 
			}
		}
		public ColorValue SetSelectedBackColor
		{ 
			set
			{
				m_oSelectedBackColor = value; 
			}
		}
		public ColorValue SetCaretColor
		{ 
			set
			{
				m_oCaretColor = value; 
			}
		}
		public string Text { get { return m_oTextData.Text; } set { SetText(value, false); } }
		public string GetCopyText 
		{ 
			get
			{
				return m_oTextData.Text.Clone() as string; 
			}
		}
		public override Vector2 Size
		{
			get
			{
				return( base.Size );
			}
			set
			{
				m_oTextData.Size = new System.Drawing.Size( (int)value.X,(int)value.Y );
				base.Size = value;
			}
		}
		public override System.Drawing.Color FontColor
		{
			get
			{
				return( base.FontColor );
			}
			set
			{
				base.FontColor = value;
				Microsoft.DirectX.Direct3D.ColorValue oFontColor = new Microsoft.DirectX.Direct3D.ColorValue( base.FontColor.R,base.FontColor.G,base.FontColor.B,base.FontColor.A );
				m_oTextColor = oFontColor;

				m_oMainLayer_FontColor.States[(int)ControlState.Normal] = oFontColor;
				m_oMainLayer_FontColor.States[(int)ControlState.Focus] = oFontColor;
			}
		}
		#endregion
	}
	public class DSThreadSafeRichTextBox
	{
		#region Properties
		private System.Drawing.Font m_oFont = null;
		private string m_sText = "";
		private int m_nSelectionStart = 0;
		private int m_nMaxLen = 0;

		private System.Windows.Forms.RichTextBox m_oRichTextBox = null;
		#endregion


		public DSThreadSafeRichTextBox()
		{
		}


		public System.Drawing.Point GetPositionFromCharIndex( int nPos )
		{
			System.Drawing.Point oPoint = System.Drawing.Point.Empty;
			Vector2 vFontSize = Vector2.Empty;
			
			try
			{
				oPoint = GetRichTextBox().GetPositionFromCharIndex( nPos );

				//vFontSize = DSResourceManager.GetGlobalInstance().GetFontSize();
				//oPoint = new Point( (int)(nPos * vFontSize.X),0 );
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}

			return( oPoint );
		}
		public int GetCharIndexFromPosition( System.Drawing.Point pPoint )
		{
			int nPos = 0;
			Vector2 vFontSize = Vector2.Empty;
			
			try
			{
				nPos = GetRichTextBox().GetCharIndexFromPosition( pPoint );

				/*vFontSize = DSResourceManager.GetGlobalInstance().GetFontSize();
				nPos = (int)( pPoint.X / vFontSize.X );
				nPos = DSMisc.Min( nPos,m_sText.Length );
				nPos = DSMisc.Max( nPos,0 );*/
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}

			return( nPos );
		}
		private System.Windows.Forms.RichTextBox GetRichTextBox()
		{
			if( m_oRichTextBox == null )
			{
				m_oRichTextBox = new System.Windows.Forms.RichTextBox();
			}
			else if( m_oRichTextBox.InvokeRequired == true )
			{
				System.Drawing.Size oSize = m_oRichTextBox.Size;				
				m_oRichTextBox = new System.Windows.Forms.RichTextBox();
				m_oRichTextBox.Size = oSize;
			}

			if( m_oFont != null )
			{
				m_oRichTextBox.Font = m_oFont;
			}
			m_oRichTextBox.Text = m_sText;

			return( m_oRichTextBox );
		}



		#region Properties
		public string Text
		{
			get
			{
				return( m_sText );
			}
			set
			{
				m_sText = value;
				m_nSelectionStart = 0;
			}
		}
		public int MaxLength
		{
			get
			{
				return( m_nMaxLen );
			}
			set
			{
				m_nMaxLen = value;
			}
		}	
		
		public int SelectionStart
		{
			get
			{
				return( m_nSelectionStart );
			}
			set
			{
				m_nSelectionStart = value;
			}
		}			

		public System.Drawing.Size Size
		{
			get
			{
				return( GetRichTextBox().Size );
			}
			set
			{
				GetRichTextBox().Size = value;
			}
		}
		public System.Drawing.Font Font
		{
			get
			{
				return( m_oFont );
			}
			set
			{
				m_oFont = value;
			}
		}
		#endregion
	}
	#region Bad DSThreadSafeRichTextBox Attempt
	/*public class DSThreadSafeRichTextBox// : System.Windows.Forms.RichTextBox
	{
		#region Properties
		private object m_oGetCallResult = null;
		private System.Windows.Forms.RichTextBox m_oTextData = null;

		public delegate void Delegate_GetCall( string sMethod );
		public delegate void Delegate_SetCall( string sMethod,object oValue );
		public delegate void Delegate_MethodCall( string sMethod,object[] oaArguments );
		#endregion


		public DSThreadSafeRichTextBox()
		{
			m_oTextData = new System.Windows.Forms.RichTextBox();
			m_oTextData.CreateControl();
		}


		public new bool Visible
		{
			get
			{
				return( (bool)GetCall( "Visible" ) );
			}
			set
			{
				SetCall( "Visible",value );
			}
		}
		public new System.Drawing.Font Font
		{
			get
			{
				return( (System.Drawing.Font)GetCall( "Font" ) );
			}
			set
			{
				SetCall( "Font",value );
			}
		}
		public new System.Windows.Forms.RichTextBoxScrollBars ScrollBars
		{
			get
			{
				return( (System.Windows.Forms.RichTextBoxScrollBars)GetCall( "ScrollBars" ) );
			}
			set
			{
				SetCall( "ScrollBars",value );
			}
		}

		public new bool Multiline
		{
			get
			{
				return( (bool)GetCall( "Multiline" ) );
			}
			set
			{
				SetCall( "Multiline",value );
			}
		}
		
		public new string Text
		{
			get
			{
				string sRetVal = (string)GetCall( "Text" );

				if( sRetVal == null )
				{
					sRetVal = "";
				}

				return( sRetVal );
			}
			set
			{
				SetCall( "Text",value );
			}
		}
		public new long MaxLength
		{
			get
			{
				return( (long)GetCall( "MaxLength" ) );
			}
			set
			{
				SetCall( "MaxLength",value );
			}
		}	
		
		public new bool WordWrap
		{
			get
			{
				return( (bool)GetCall( "WordWrap" ) );
			}
			set
			{
				SetCall( "WordWrap",value );
			}
		}	
		public new int SelectionStart
		{
			get
			{
				return( (int)GetCall( "SelectionStart" ) );
			}
			set
			{
				SetCall( "SelectionStart",value );
			}
		}			

		public new System.Drawing.Size Size
		{
			get
			{
				return( (System.Drawing.Size)GetCall( "Size" ) );
			}
			set
			{
				SetCall( "Size",value );
			}
		}	

		public new System.Drawing.Point GetPositionFromCharIndex( int i )
		{
			System.Drawing.Point oPoint = System.Drawing.Point.Empty;

			try
			{
				oPoint = (System.Drawing.Point)MethodCall( "GetPositionFromCharIndex",new object[ 1 ]{i} );
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}
			return( oPoint );
		}
		public new int GetCharIndexFromPosition( System.Drawing.Point p )
		{
			return( (int)MethodCall( "GetCharIndexFromPosition",new object[ 1 ]{p} ) );
		}


		private object GetCall( string sMethod )
		{
			this.BeginInvoke( new Delegate_GetCall(this.DelegateCall_GetCall),
							  new object[]{sMethod} );

			return( m_oGetCallResult );
		}
		private void DelegateCall_GetCall( string sMethod )
		{
			object[] oaArguments = new object[ 0 ];

			m_oGetCallResult = m_oTextData.GetType().InvokeMember( sMethod, 
							BindingFlags.Default | BindingFlags.GetProperty,
							null, this, oaArguments );
		}
		private void SetCall( string sMethod,object oValue )
		{
			try
			{
				this.BeginInvoke( new Delegate_SetCall(this.DelegateCall_SetCall),
								  new object[]{sMethod,oValue} );
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}
		}
		private void DelegateCall_SetCall( string sMethod,object oValue )
		{
			object[] oaArguments = new object[ 1 ]{ oValue };

			m_oTextData.GetType().InvokeMember( sMethod, 
							BindingFlags.Default | BindingFlags.SetProperty,
							null, this, oaArguments );
		}
		private object MethodCall( string sMethod,object[] oaArguments )
		{
			this.BeginInvoke( new Delegate_MethodCall(this.DelegateCall_MethodCall),
							  new object[]{sMethod,oaArguments} );

			return( m_oGetCallResult );
		}
		private void DelegateCall_MethodCall( string sMethod,object[] oaArguments )
		{
			long i = 0;
			i = oaArguments.Length;
			m_oGetCallResult = m_oTextData.GetType().InvokeMember( sMethod, 
						BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
						null, m_oTextData, oaArguments );
		}
	}*/
	#endregion
	#endregion
	#endregion
}