Click here to Skip to main content
15,896,726 members
Articles / Programming Languages / Visual Basic

Mathemathics Framework

Rate me:
Please Sign up or sign in to vote.
4.76/5 (56 votes)
16 Sep 2008CPOL6 min read 75.5K   6.2K   171  
.NET Mathematical Framework
//--------------------------------------------------------------------------------------
// File: DXMUTGui.cs
//
// DirectX SDK Managed Direct3D GUI Sample Code
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
using System;
using System.Collections;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace Microsoft.Samples.DirectX.UtilityToolkit
{
    /// <summary>
    /// Predefined control types
    /// </summary>
    public enum ControlType
    {
        StaticText,
        Button,
        CheckBox,
        RadioButton,
        ComboBox,
        Slider,
        ListBox,
        EditBox,
        Scrollbar,
    }

    /// <summary>
    /// Possible states of a control
    /// </summary>
    public enum ControlState
    {
        Normal,
        Disabled,
        Hidden,
        Focus,
        MouseOver,
        Pressed,
        LastState // Should always be last
    }

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

        /// <summary>Initialize the color blending</summary>
        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;
        }
        /// <summary>Initialize the color blending</summary>
        public void Initialize(ColorValue defaultColor) { Initialize( defaultColor, new ColorValue(0.5f, 0.5f, 0.5f, 0.75f),new ColorValue()); }

        /// <summary>Blend the colors together</summary>
        public void Blend(ControlState state, float elapsedTime, float rate)
        {
            if ((States == null) || (States.Length == 0) )
                return; // Nothing to do

            ColorValue destColor = States[(int)state];
            Current = ColorOperator.Lerp(Current, destColor, 1.0f - (float)Math.Pow(rate, 30 * elapsedTime) );
        }
        /// <summary>Blend the colors together</summary>
        public void Blend(ControlState state, float elapsedTime) { Blend(state, elapsedTime, 0.7f); }
    }

    /// <summary>
    /// Contains all the display information for a given control type
    /// </summary>
    public struct ElementHolder
    {
        public ControlType ControlType;
        public uint ElementIndex;
        public Element Element;
    }

    /// <summary>
    /// Contains all the display tweakables for a sub-control
    /// </summary>
    public class Element : ICloneable
    {
        #region Magic Numbers
        #endregion

        #region Instance Data
        public uint TextureIndex; // Index of the texture for this Element 
        public uint FontIndex; // Index of the font for this Element 
        public DrawTextFormat textFormat; // The Format argument to draw text

        public System.Drawing.Rectangle textureRect; // Bounding rectangle of this element on the composite texture

        public BlendColor TextureColor;
        public BlendColor FontColor;
        #endregion

        /// <summary>Set the texture</summary>
        public void SetTexture(uint tex, System.Drawing.Rectangle texRect, ColorValue defaultTextureColor)
        {
            // Store data
            TextureIndex = tex;
            textureRect = texRect;
            TextureColor.Initialize(defaultTextureColor);
        }
        /// <summary>Set the texture</summary>
        public void SetTexture(uint tex, System.Drawing.Rectangle texRect) { SetTexture(tex, texRect, Dialog.WhiteColorValue); }
        /// <summary>Set the font</summary>
        public void SetFont(uint font, ColorValue defaultFontColor, DrawTextFormat format)
        {
            // Store data
            FontIndex = font;
            textFormat = format;
            FontColor.Initialize(defaultFontColor);
        }
        /// <summary>Set the font</summary>
        public void SetFont(uint font){ SetFont(font, Dialog.WhiteColorValue, DrawTextFormat.Center | DrawTextFormat.VerticalCenter ); }
        /// <summary>
        /// Refresh this element
        /// </summary>
        public void Refresh()
        {
            if (TextureColor.States != null) 
                TextureColor.Current = TextureColor.States[(int)ControlState.Hidden];
            if (FontColor.States != null) 
                FontColor.Current = FontColor.States[(int)ControlState.Hidden];
        }

        #region ICloneable Members
        /// <summary>Clone an object</summary>
        public Element Clone() 
        { 
            Element e = new Element();
            e.TextureIndex = this.TextureIndex;
            e.FontIndex = this.FontIndex;
            e.textFormat = this.textFormat;
            e.textureRect = this.textureRect; 
            e.TextureColor = this.TextureColor;
            e.FontColor = this.FontColor;

            return e;
        }
        /// <summary>Clone an object</summary>
        object ICloneable.Clone() { throw new NotSupportedException("Use the strongly typed clone.");}

        #endregion
    }


    #region Dialog Resource Manager
    /// <summary>
    /// Structure for shared textures
    /// </summary>
    public class TextureNode 
    {
        public string Filename;
        public Texture Texture;
        public uint Width;
        public uint Height;
    }

    /// <summary>
    /// Structure for shared fonts
    /// </summary>
    public class FontNode 
    {
        public string FaceName;
        public Font Font;
        public uint Height;
        public FontWeight Weight;
    }

    /// <summary>
    /// Manages shared resources of dialogs
    /// </summary>
    public sealed class DialogResourceManager
    {
        private StateBlock dialogStateBlock;  // Stateblock shared amongst all dialogs
        private Sprite dialogSprite; // Sprite used for drawing
        public StateBlock StateBlock { get { return dialogStateBlock; } }
        public Sprite Sprite { get { return dialogSprite; } }
        private Device device; // Device

        // Lists of textures/fonts
        private ArrayList textureCache = new ArrayList();
        private ArrayList fontCache = new ArrayList();

        #region Creation
        /// <summary>Do not allow creation</summary>
        private DialogResourceManager()  {
            device = null;
            dialogSprite = null;
            dialogStateBlock = null;
        } 

        private static DialogResourceManager localObject = null;
        public static DialogResourceManager GetGlobalInstance()
        {
            if (localObject == null)
                localObject = new DialogResourceManager();

            return localObject;
        }
        #endregion

        /// <summary>Gets a font node from the cache</summary>
        public FontNode GetFontNode(int index) { return fontCache[index] as FontNode; }
        /// <summary>Gets a texture node from the cache</summary>
        public TextureNode GetTextureNode(int index) { return textureCache[index] as TextureNode; }
        /// <summary>Gets the device</summary>
        public Device Device { get { return device; } }

        /// <summary>
        /// Adds a font to the resource manager
        /// </summary>
        public int AddFont(string faceName, uint height, FontWeight weight)
        {
            // See if this font exists
            for(int i = 0; i < fontCache.Count; i++)
            {
                FontNode fn = fontCache[i] as FontNode;
                if ( (string.Compare(fn.FaceName, faceName, true) == 0) &&
                    fn.Height == height &&
                    fn.Weight == weight)
                {
                    // Found it
                    return i;
                }
            }

            // Doesn't exist, add a new one and try to create it
            FontNode newNode = new FontNode();
            newNode.FaceName = faceName;
            newNode.Height = height;
            newNode.Weight = weight;
            fontCache.Add(newNode);

            int fontIndex = fontCache.Count-1;
            // If a device is available, try to create immediately
            if (device != null)
                CreateFont(fontIndex);

            return fontIndex;
        }
        /// <summary>
        /// Adds a texture to the resource manager
        /// </summary>
        public int AddTexture(string filename)
        {
            // See if this font exists
            for(int i = 0; i < textureCache.Count; i++)
            {
                TextureNode tn = textureCache[i] as TextureNode;
                if (string.Compare(tn.Filename, filename, true) == 0)
                {
                    // Found it
                    return i;
                }
            }
            // Doesn't exist, add a new one and try to create it
            TextureNode newNode = new TextureNode();
            newNode.Filename = filename;
            textureCache.Add(newNode);

            int texIndex = textureCache.Count-1;

            // If a device is available, try to create immediately
            if (device != null)
                CreateTexture(texIndex);

            return texIndex;

        }

        /// <summary>
        /// Creates a font
        /// </summary>
        public void CreateFont(int font)
        {
            // Get the font node here
            FontNode fn = GetFontNode(font);
            if (fn.Font != null)
                fn.Font.Dispose(); // Get rid of this

            // Create the new font
            fn.Font = new Font(device, (int)fn.Height, 0, fn.Weight, 1, false, CharacterSet.Default,
                Precision.Default, FontQuality.Default, PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare,
                fn.FaceName);
        }

        /// <summary>
        /// Creates a texture
        /// </summary>
        public void CreateTexture(int tex)
        {
            // Get the texture node here
            TextureNode tn = GetTextureNode(tex);

            // Make sure there's a texture to create
            if ((tn.Filename == null) || (tn.Filename.Length == 0))
                return;

            // Find the texture
            string path = Utility.FindMediaFile(tn.Filename);

            // Create the new texture
            ImageInformation info = new ImageInformation();
            tn.Texture = TextureLoader.FromFile(device, path, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None,
                Format.Unknown, Pool.Managed, (Filter)D3DX.Default, (Filter)D3DX.Default, 0, ref info);

            // Store dimensions
            tn.Width = (uint)info.Width;
            tn.Height = (uint)info.Height;

        }

        #region Device event callbacks
        /// <summary>
        /// Called when the device is created
        /// </summary>
        public void OnCreateDevice(Device d) 
        {
            // Store device
            device = d;

            // create fonts and textures
            for (int i = 0; i < fontCache.Count; i++)
                CreateFont(i);

            for (int i = 0; i < textureCache.Count; i++)
                CreateTexture(i);

            dialogSprite = new Sprite(d); // Create the sprite
        } 
        /// <summary>
        /// Called when the device is reset
        /// </summary>
        public void OnResetDevice(Device device)
        {
            foreach(FontNode fn in fontCache)
                fn.Font.OnResetDevice();

            if (dialogSprite != null)
                dialogSprite.OnResetDevice();
            
            // Create new state block
            dialogStateBlock = new StateBlock(device, StateBlockType.All);
        }

        /// <summary>
        /// Clear any resources that need to be lost
        /// </summary>
        public void OnLostDevice()
        {
            foreach(FontNode fn in fontCache)
            {
                if ( (fn.Font != null) && (!fn.Font.Disposed) )
                    fn.Font.OnLostDevice();
            }

            if (dialogSprite != null)
                dialogSprite.OnLostDevice();

            if (dialogStateBlock != null)
            {
                dialogStateBlock.Dispose();
                dialogStateBlock = null;
            }
        }
        
        /// <summary>
        /// Destroy any resources and clear the caches
        /// </summary>
        public void OnDestroyDevice()
        {
            foreach(FontNode fn in fontCache)
            {
                if (fn.Font != null)
                    fn.Font.Dispose();
            }
            
            foreach(TextureNode tn in textureCache)
            {
                if (tn.Texture != null)
                    tn.Texture.Dispose();
            }

            if (dialogSprite != null)
            {
                dialogSprite.Dispose();
                dialogSprite = null;
            }

            if (dialogStateBlock != null)
            {
                dialogStateBlock.Dispose();
                dialogStateBlock = null;
            }
        }

        #endregion
    }

    #endregion

    /// <summary>
    /// All controls must be assigned to a dialog, which handles
    /// input and rendering for the controls.
    /// </summary>
    public class Dialog
    {
        #region Static Data
        public const int WheelDelta = 120;
        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 static Control controlFocus = null; // The control which has focus
        private static Control controlMouseOver = null; // The control which is hovered over
        private static Control controlMouseDown = null; // The control which the mouse was pressed on

        private static double timeRefresh = 0.0;
        /// <summary>Set the static refresh time</summary>
        public static void SetRefreshTime(float time) { timeRefresh = time; }
        #endregion

        #region Instance Data
        // Sample framework
        private Framework parent = null; 
        public Framework SampleFramework { get { return parent; } }

        // Vertex information
        private CustomVertex.TransformedColoredTextured[] vertices;

        // Timing
        private double timeLastRefresh;

        // Control/Elements
        private ArrayList controlList = new ArrayList();
        private ArrayList defaultElementList = new ArrayList();

        // Captions
        private bool hasCaption;
        private string caption;
        private int captionHeight;
        private Element captionElement;
        private bool isDialogMinimized;

        // Dialog information
        private int dialogX, dialogY, width, height;
        // Colors
        private ColorValue topLeftColor, topRightColor, bottomLeftColor, bottomRightColor;
        
        // Fonts/Textures
        private ArrayList textureList = new ArrayList(); // Index into texture cache
        private ArrayList fontList = new ArrayList(); // Index into font cache

        // Dialogs
        private Dialog nextDialog;
        private Dialog prevDialog;

        // User Input control
        private bool usingNonUserEvents;
        private bool usingKeyboardInput;
        private bool usingMouseInput;
        #endregion

        #region Simple Properties/Methods
        /// <summary>Is the dilaog using non user events</summary>
        public bool IsUsingNonUserEvents { get { return usingNonUserEvents; } set { usingNonUserEvents = value; } }
        /// <summary>Is the dilaog using keyboard input</summary>
        public bool IsUsingKeyboardInput { get { return usingKeyboardInput; } set { usingKeyboardInput = value; } }
        /// <summary>Is the dilaog using mouse input</summary>
        public bool IsUsingMouseInput { get { return usingMouseInput; } set { usingMouseInput = value; } }
        /// <summary>Is the dilaog minimized</summary>
        public bool IsMinimized { get { return isDialogMinimized; } set { isDialogMinimized = value; } }
        /// <summary>Called to set dialog's location</summary>
        public void SetLocation(int x, int y) { dialogX = x; dialogY = y; UpdateVertices(); }
        /// <summary>The dialog's location</summary>
        public System.Drawing.Point Location { 
            get {return new System.Drawing.Point(dialogX, dialogY); } 
            set { dialogX = value.X; dialogY = value.Y; UpdateVertices(); } 
        }

        /// <summary>Called to set dialog's size</summary>
        public void SetSize(int w, int h) { width = w; height = h; UpdateVertices();}
        /// <summary>Dialogs width</summary>
        public int Width { get { return width; } set { width = value; } }
        /// <summary>Dialogs height</summary>
        public int Height { get { return height; } set { height = value; } }
        /// <summary>Called to set dialog's caption</summary>
        public void SetCaptionText(string text) { caption = text; }
        /// <summary>The dialog's caption height</summary>
        public int CaptionHeight { get { return captionHeight; } set { captionHeight = value; } }
        /// <summary>Called to set dialog's caption enabled state</summary>
        public void SetCaptionEnabled(bool isEnabled) { hasCaption = isEnabled; }
        /// <summary>Called to set dialog's border colors</summary>
        public void SetBackgroundColors(ColorValue topLeft, ColorValue topRight, ColorValue bottomLeft, ColorValue bottomRight) 
        { 
            topLeftColor = topLeft; topRightColor = topRight; bottomLeftColor = bottomLeft; bottomRightColor = bottomRight;
            UpdateVertices();
        }
        /// <summary>Called to set dialog's border colors</summary>
        public void SetBackgroundColors(ColorValue allCorners) { SetBackgroundColors(allCorners, allCorners, allCorners, allCorners); }

        #endregion

        /// <summary>
        /// Create a new instance of the dialog class
        /// </summary>
        public Dialog(Framework sample)
        {
            parent = sample; // store this for later use
            // Initialize to default state
            dialogX = 0; dialogY = 0; width = 0; height = 0;
            hasCaption = false; isDialogMinimized = false; 
            caption = string.Empty;
            captionHeight = 18;

            topLeftColor = topRightColor = bottomLeftColor = bottomRightColor = new ColorValue();

            timeLastRefresh = 0.0f;
            
            nextDialog = this; // Only one dialog
            prevDialog = this;  // Only one dialog

            usingNonUserEvents = false;
            usingKeyboardInput = false;
            usingMouseInput = true;

            InitializeDefaultElements();
        }

        /// <summary>
        /// Initialize the default elements for this dialog
        /// </summary>
        private void InitializeDefaultElements()
        {
            SetTexture(0, "UI\\DXUTControls.dds");
            SetFont(0, "Arial", 14, FontWeight.Normal);

            //-------------------------------------
            // Element for the caption
            //-------------------------------------
            captionElement = new Element();
            captionElement.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.VerticalCenter);
            captionElement.SetTexture(0, System.Drawing.Rectangle.FromLTRB(17, 269, 241, 287));
            captionElement.TextureColor.States[(int)ControlState.Normal] = WhiteColorValue;
            captionElement.FontColor.States[(int)ControlState.Normal] = WhiteColorValue;
            // Pre-blend as we don't need to transition the state
            captionElement.TextureColor.Blend(ControlState.Normal, 10.0f);
            captionElement.FontColor.Blend(ControlState.Normal, 10.0f);

            Element e = new Element();

            //-------------------------------------
            // StaticText
            //-------------------------------------
            e.SetFont(0);
            e.FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.75f, 0.75f, 0.75f, 0.75f);
            // Assign the element
            SetDefaultElement(ControlType.StaticText, StaticText.TextElement, e);

            //-------------------------------------
            // Button - Button
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(0, 0, 136, 54));
            e.SetFont(0);
            e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
            e.TextureColor.States[(int)ControlState.Pressed] = new ColorValue(1.0f, 1.0f, 1.0f, 0.85f);
            e.FontColor.States[(int)ControlState.MouseOver] = BlackColorValue;
            // Assign the element
            SetDefaultElement(ControlType.Button, Button.ButtonLayer, e);

            //-------------------------------------
            // Button - Fill Layer
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(136, 0, 252, 54), TransparentWhite);
            e.TextureColor.States[(int)ControlState.MouseOver] = new ColorValue(1.0f, 1.0f, 1.0f, 0.6f);
            e.TextureColor.States[(int)ControlState.Pressed] = new ColorValue(0,0,0, 0.25f);
            e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.05f);
            // Assign the element
            SetDefaultElement(ControlType.Button, Button.FillLayer, e);


            //-------------------------------------
            // CheckBox - Box
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(0, 54, 27, 81));
            e.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.VerticalCenter);
            e.FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.8f);
            e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
            e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.8f);
            e.TextureColor.States[(int)ControlState.Pressed] = WhiteColorValue;
            // Assign the element
            SetDefaultElement(ControlType.CheckBox, Checkbox.BoxLayer, e);

            //-------------------------------------
            // CheckBox - Check
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(27, 54, 54, 81));
            // Assign the element
            SetDefaultElement(ControlType.CheckBox, Checkbox.CheckLayer, e);

            //-------------------------------------
            // RadioButton - Box
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(54, 54, 81, 81));
            e.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.VerticalCenter);
            e.FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.8f);
            e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
            e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.8f);
            e.TextureColor.States[(int)ControlState.Pressed] = WhiteColorValue;
            // Assign the element
            SetDefaultElement(ControlType.RadioButton, RadioButton.BoxLayer, e);

            //-------------------------------------
            // RadioButton - Check
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(81, 54, 108, 81));
            // Assign the element
            SetDefaultElement(ControlType.RadioButton, RadioButton.CheckLayer, e);

            //-------------------------------------
            // ComboBox - Main
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(7, 81, 247, 123));
            e.SetFont(0);
            e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(0.8f, 0.8f, 0.8f, 0.55f);
            e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(0.95f, 0.95f, 0.95f, 0.6f);
            e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.25f);
            e.FontColor.States[(int)ControlState.MouseOver] = new ColorValue(0,0,0,1.0f);
            e.FontColor.States[(int)ControlState.Pressed] = new ColorValue(0,0,0,1.0f);
            e.FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.8f);
            // Assign the element
            SetDefaultElement(ControlType.ComboBox, ComboBox.MainLayer, e);

            //-------------------------------------
            // ComboBox - Button
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(98, 189, 151, 238));
            e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
            e.TextureColor.States[(int)ControlState.Pressed] = new ColorValue(0.55f, 0.55f, 0.55f, 1.0f);
            e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.75f);
            e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(1.0f, 1.0f, 1.0f, 0.25f);
            // Assign the element
            SetDefaultElement(ControlType.ComboBox, ComboBox.ComboButtonLayer, e);

            //-------------------------------------
            // ComboBox - Dropdown
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(13, 123, 241, 160));
            e.SetFont(0, BlackColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
            // Assign the element
            SetDefaultElement(ControlType.ComboBox, ComboBox.DropdownLayer, e);

            //-------------------------------------
            // ComboBox - Selection
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(12, 163, 239, 183));
            e.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
            // Assign the element
            SetDefaultElement(ControlType.ComboBox, ComboBox.SelectionLayer, e);

            //-------------------------------------
            // Slider - Track
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(1, 187, 93, 228));
            e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
            e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.75f);
            e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(1.0f, 1.0f, 1.0f, 0.25f);
            // Assign the element
            SetDefaultElement(ControlType.Slider, Slider.TrackLayer, e);

            //-------------------------------------
            // Slider - Button
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(151, 193, 192, 234));
            // Assign the element
            SetDefaultElement(ControlType.Slider, Slider.ButtonLayer, e);

            //-------------------------------------
            // Scrollbar - Track
            //-------------------------------------
            int scrollBarStartX = 196;
            int scrollBarStartY = 191;
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(scrollBarStartX + 0, scrollBarStartY + 21, scrollBarStartX + 22, scrollBarStartY + 32));
            // Assign the element
            SetDefaultElement(ControlType.Scrollbar, ScrollBar.TrackLayer, e);

            //-------------------------------------
            // Scrollbar - Up Arrow
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(scrollBarStartX + 0, scrollBarStartY + 1, scrollBarStartX + 22, scrollBarStartY + 21));
            e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 1.0f);
            // Assign the element
            SetDefaultElement(ControlType.Scrollbar, ScrollBar.UpButtonLayer, e);

            //-------------------------------------
            // Scrollbar - Down Arrow
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(scrollBarStartX + 0, scrollBarStartY + 32, scrollBarStartX + 22, scrollBarStartY + 53));
            e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 1.0f);
            // Assign the element
            SetDefaultElement(ControlType.Scrollbar, ScrollBar.DownButtonLayer, e);

            //-------------------------------------
            // Scrollbar - Button
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(220, 192, 238, 234));
            // Assign the element
            SetDefaultElement(ControlType.Scrollbar, ScrollBar.ThumbLayer, e);


            //-------------------------------------
            // EditBox
            //-------------------------------------
            // Element assignment:
            //   0 - text area
            //   1 - top left border
            //   2 - top border
            //   3 - top right border
            //   4 - left border
            //   5 - right border
            //   6 - lower left border
            //   7 - lower border
            //   8 - lower right border
            e.SetFont(0, BlackColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
            
            // Assign the styles
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(14, 90, 241, 113));
            SetDefaultElement(ControlType.EditBox, EditBox.TextLayer, e);
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(8, 82, 14, 90));
            SetDefaultElement(ControlType.EditBox, EditBox.TopLeftBorder, e);
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(14, 82, 241, 90));
            SetDefaultElement(ControlType.EditBox, EditBox.TopBorder, e);
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(241, 82, 246, 90));
            SetDefaultElement(ControlType.EditBox, EditBox.TopRightBorder, e);
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(8, 90, 14, 113));
            SetDefaultElement(ControlType.EditBox, EditBox.LeftBorder, e);
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(241, 90, 246, 113));
            SetDefaultElement(ControlType.EditBox, EditBox.RightBorder, e);
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(8, 113, 14, 121));
            SetDefaultElement(ControlType.EditBox, EditBox.LowerLeftBorder, e);
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(14, 113, 241, 121));
            SetDefaultElement(ControlType.EditBox, EditBox.LowerBorder, e);
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(241, 113, 246, 121));
            SetDefaultElement(ControlType.EditBox, EditBox.LowerRightBorder, e);


            //-------------------------------------
            // Listbox - Main
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(13, 123, 241, 160));
            e.SetFont(0, BlackColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
            // Assign the element
            SetDefaultElement(ControlType.ListBox, ListBox.MainLayer, e);

            //-------------------------------------
            // Listbox - Selection
            //-------------------------------------
            e.SetTexture(0, System.Drawing.Rectangle.FromLTRB(16, 166, 240, 183));
            e.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
            // Assign the element
            SetDefaultElement(ControlType.ListBox, ListBox.SelectionLayer, e);
        }

        /// <summary>Removes all controls from this dialog</summary>
        public void RemoveAllControls()
        {
            controlList.Clear();
            if ( (controlFocus != null) && (controlFocus.Parent == this) )
                controlFocus = null;
            
            controlMouseOver = null;
        }

        /// <summary>Clears the radio button group</summary>
        public void ClearRadioButtonGroup(uint groupIndex)
        {
            // Find all radio buttons with the given group number
            foreach(Control c in controlList)
            {
                if (c.ControlType == ControlType.RadioButton)
                {
                    RadioButton rb = c as RadioButton;
                    // Clear the radio button checked setting
                    if (rb.ButtonGroup == groupIndex)
                        rb.SetChecked(false, false);
                }
            }
        }

        /// <summary>Clears the combo box of all items</summary>
        public void ClearComboBox(int id)
        {
            ComboBox comboBox = GetComboBox(id);
            if (comboBox == null)
                return;

            comboBox.Clear();
        }

        #region Message handling
        private static bool isDragging;
        /// <summary>
        /// Handle messages for this dialog
        /// </summary>
        public bool MessageProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            // If caption is enable, check for clicks in the caption area.
            if (hasCaption)
            {
                if (msg == NativeMethods.WindowMessage.LeftButtonDown || msg == NativeMethods.WindowMessage.LeftButtonDoubleClick)
                {
                    // Current mouse position
                    short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
                    short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());

                    if (mouseX >= dialogX && mouseX < dialogX + width && 
                        mouseY >= dialogY && mouseY < dialogY + captionHeight)
                    {
                        isDragging = true;
                        NativeMethods.SetCapture(hWnd);
                        return true;
                    }
                }
                else if ( (msg == NativeMethods.WindowMessage.LeftButtonUp) && isDragging)
                {
                    // Current mouse position
                    short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
                    short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());

                    if (mouseX >= dialogX && mouseX < dialogX + width && 
                        mouseY >= dialogY && mouseY < dialogY + captionHeight)
                    {
                        NativeMethods.ReleaseCapture();
                        isDragging = false;
                        return true;
                    }
                }
            }
            
            // If the dialog is minimized, don't send any messages to controls.
            if (isDialogMinimized)
                return false;

            // If a control is in focus, it belongs to this dialog, and it's enabled, then give
            // it the first chance at handling the message.
            if (controlFocus != null && 
                controlFocus.Parent == this && 
                controlFocus.IsEnabled)
            {
                // If the control MsgProc handles it, then we don't.
                if (controlFocus.MsgProc(hWnd, msg, wParam, lParam))
                    return true;
            }

            switch(msg)
            {
                // Call OnFocusIn()/OnFocusOut() of the control that currently has the focus
                // as the application is activated/deactivated.  This matches the Windows
                // behavior.
                case NativeMethods.WindowMessage.ActivateApplication:
                {
                    if (controlFocus != null && 
                        controlFocus.Parent == this && 
                        controlFocus.IsEnabled)
                    {
                        if (wParam != IntPtr.Zero)
                            controlFocus.OnFocusIn();
                        else
                            controlFocus.OnFocusOut();
                    }
                }
                    break;

                // Keyboard messages
                case NativeMethods.WindowMessage.KeyDown:
                case NativeMethods.WindowMessage.SystemKeyDown:
                case NativeMethods.WindowMessage.KeyUp:
                case NativeMethods.WindowMessage.SystemKeyUp:
                {
                    // If a control is in focus, it belongs to this dialog, and it's enabled, then give
                    // it the first chance at handling the message.
                    if (controlFocus != null && 
                        controlFocus.Parent == this && 
                        controlFocus.IsEnabled)
                    {
                        // If the control MsgProc handles it, then we don't.
                        if (controlFocus.HandleKeyboard(msg, wParam, lParam))
                            return true;
                    }

                    // Not yet handled, see if this matches a control's hotkey
                    if (msg == NativeMethods.WindowMessage.KeyUp)
                    {
                        foreach(Control c in controlList)
                        {
                            // Was the hotkey hit?
                            if (c.Hotkey == (System.Windows.Forms.Keys)wParam.ToInt32())
                            {
                                // Yup!
                                c.OnHotKey();
                                return true;
                            }
                        }
                    }
                    if (msg == NativeMethods.WindowMessage.KeyDown)
                    {
                        // If keyboard input is not enabled, this message should be ignored
                        if (!usingKeyboardInput)
                            return false;

                        System.Windows.Forms.Keys key = (System.Windows.Forms.Keys)wParam.ToInt32();
                        switch(key)
                        {
                            case System.Windows.Forms.Keys.Right:
                            case System.Windows.Forms.Keys.Down:
                                if (controlFocus != null)
                                {
                                    OnCycleFocus(true);
                                    return true;
                                }
                                break;
                            case System.Windows.Forms.Keys.Left:
                            case System.Windows.Forms.Keys.Up:
                                if (controlFocus != null)
                                {
                                    OnCycleFocus(false);
                                    return true;
                                }
                                break;
                            case System.Windows.Forms.Keys.Tab:
                                if (controlFocus == null)
                                {
                                    FocusDefaultControl();
                                }
                                else
                                {
                                    bool shiftDown = NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey);

                                    OnCycleFocus(!shiftDown);
                                }
                                return true;
                        }
                    }
                }
                    break;

                // Mouse messages
                case NativeMethods.WindowMessage.MouseMove:
                case NativeMethods.WindowMessage.MouseWheel:
                case NativeMethods.WindowMessage.LeftButtonUp:
                case NativeMethods.WindowMessage.LeftButtonDown:
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                case NativeMethods.WindowMessage.RightButtonUp:
                case NativeMethods.WindowMessage.RightButtonDown:
                case NativeMethods.WindowMessage.RightButtonDoubleClick:
                case NativeMethods.WindowMessage.MiddleButtonUp:
                case NativeMethods.WindowMessage.MiddleButtonDown:
                case NativeMethods.WindowMessage.MiddleButtonDoubleClick:
                case NativeMethods.WindowMessage.XButtonUp:
                case NativeMethods.WindowMessage.XButtonDown:
                case NativeMethods.WindowMessage.XButtonDoubleClick:
                {
                    // If not accepting mouse input, return false to indicate the message should still 
                    // be handled by the application (usually to move the camera).
                    if (!usingMouseInput)
                        return false;

                    // Current mouse position
                    short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
                    short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
                    System.Drawing.Point mousePoint = new System.Drawing.Point(mouseX, mouseY);
                    // Offset mouse point
                    mousePoint.X -= dialogX;
                    mousePoint.Y -= dialogY;

                    // If caption is enabled, offset the Y coordinate by the negative of its height.
                    if (hasCaption)
                        mousePoint.Y -= captionHeight;

                    // If a control is in focus, it belongs to this dialog, and it's enabled, then give
                    // it the first chance at handling the message.
                    if (controlFocus != null && 
                        controlFocus.Parent == this && 
                        controlFocus.IsEnabled)
                    {
                        // If the control MsgProc handles it, then we don't.
                        if (controlFocus.HandleMouse(msg, mousePoint, wParam, lParam))
                            return true;
                    }

                    // Not yet handled, see if the mouse is over any controls
                    Control control = GetControlAtPoint(mousePoint);
                    if ((control != null) && (control.IsEnabled))
                    {
                        // Let the control handle the mouse if it wants (and return true if it handles it)
                        if (control.HandleMouse(msg, mousePoint, wParam, lParam))
                            return true;
                    }
                    else
                    {
                        // Mouse not over any controls in this dialog, if there was a control
                        // which had focus it just lost it
                        if (msg == NativeMethods.WindowMessage.LeftButtonDown &&
                            controlFocus != null &&
                            controlFocus.Parent == this)
                        {
                            controlFocus.OnFocusOut();
                            controlFocus = null;
                        }
                    }

                    // Still not handled, hand this off to the dialog. Return false to indicate the
                    // message should still be handled by the application (usually to move the camera).
                    switch(msg)
                    {
                        case NativeMethods.WindowMessage.MouseMove:
                            OnMouseMove(mousePoint);
                            return false;
                    }


                }
                    break;
            }

            // Didn't handle this message
            return false;
        }

        /// <summary>
        /// Handle mouse moves
        /// </summary>
        private void OnMouseMove(System.Drawing.Point pt)
        {
            // If the mouse was previously hovering over a control, it's either
            // still over the control or has left
            if (controlMouseDown != null)
            {
                // If another dialog owns this control then let that dialog handle it
                if (controlMouseDown.Parent != this )
                    return;

                // If the same control is still under the mouse, nothing needs to be done
                if (controlMouseDown.ContainsPoint(pt))
                    return;
           
                // Mouse has moved outside the control, notify the control and continue
                controlMouseDown.OnMouseExit();
                controlMouseDown = null;
            }

            // Figure out which control the mouse is over now
            Control control = GetControlAtPoint(pt);
            if (control != null)
            {
                controlMouseDown = control;
                controlMouseDown.OnMouseEnter();
            }
        }
        #endregion
        
        #region Focus
        /// <summary>
        /// Request that this control has focus
        /// </summary>
        public static void RequestFocus(Control control)
        {
            if (controlFocus == control)
                return; // Already does

            if (!control.CanHaveFocus)
                return; // Can't have focus

            if (controlFocus != null)
                controlFocus.OnFocusOut();

            // Set the control focus now
            control.OnFocusIn();
            controlFocus = control;
        }

        /// <summary>
        /// Clears focus of the dialog
        /// </summary>
        public static void ClearFocus()
        {
            if (controlFocus != null)
            {
                controlFocus.OnFocusOut();
                controlFocus = null;
            }
        }
        /// <summary>
        /// Cycles focus to the next available control
        /// </summary>
        private void OnCycleFocus(bool forward)
        {
            // This should only be handled by the dialog which owns the focused control, and 
            // only if a control currently has focus
            if (controlFocus == null || controlFocus.Parent != this )
                return;

            Control control = controlFocus;
            // Go through a bunch of controls
            for (int i = 0; i < 0xffff; i++)
            {
                control = (forward) ? GetNextControl(control) : GetPreviousControl(control);

                // If we've gone in a full circle, focus won't change
                if (control == controlFocus)
                    return;

                // If the dialog accepts keybord input and the control can have focus then
                // move focus
                if (control.Parent.IsUsingKeyboardInput && control.CanHaveFocus)
                {
                    controlFocus.OnFocusOut();
                    controlFocus = control;
                    controlFocus.OnFocusIn();
                    return;
                }
            }

            throw new InvalidOperationException("Multiple dialogs are improperly chained together.");
        }

        /// <summary>
        /// Gets the next control
        /// </summary>
        private static Control GetNextControl(Control control)
        {
            int index = (int)control.index + 1;

            Dialog dialog = control.Parent;
            
            // Cycle through dialogs in the loop to find the next control. Note
            // that if only one control exists in all looped dialogs it will
            // be the returned 'next' control.
            while (index >= (int)dialog.controlList.Count)
            {
                dialog = dialog.nextDialog;
                index = 0;
            }

            return dialog.controlList[index] as Control;
        }
        /// <summary>
        /// Gets the previous control
        /// </summary>
        private static Control GetPreviousControl(Control control)
        {
            int index = (int)control.index - 1;

            Dialog dialog = control.Parent;
            
            // Cycle through dialogs in the loop to find the next control. Note
            // that if only one control exists in all looped dialogs it will
            // be the returned 'previous' control.
            while (index < 0)
            {
                dialog = dialog.prevDialog;
                if (dialog == null)
                    dialog = control.Parent;

                index = dialog.controlList.Count - 1;
            }

            return dialog.controlList[index] as Control;
        }
        /// <summary>
        /// Sets focus to the default control of a dialog
        /// </summary>
        private void FocusDefaultControl()
        {
            // Check for a default control in this dialog
            foreach(Control c in controlList)
            {
                if (c.isDefault)
                {
                    // Remove focus from the current control
                    ClearFocus();

                    // Give focus to the default control
                    controlFocus = c;
                    controlFocus.OnFocusIn();
                    return;
                }
            }
        }
        #endregion

        #region Controls Methods/Properties
        /// <summary>Sets the control enabled property</summary>
        public void SetControlEnable(int id, bool isenabled)
        {
            Control c = GetControl(id);
            if (c == null)
                return; // No control to set

            c.IsEnabled = isenabled;
        }
        /// <summary>Gets the control enabled property</summary>
        public bool GetControlEnable(int id)
        {
            Control c = GetControl(id);
            if (c == null)
                return false; // No control to get

            return c.IsEnabled;
        }

        /// <summary>Returns the control located at a point (if one exists)</summary>
        public Control GetControlAtPoint(System.Drawing.Point pt)
        {
            foreach(Control c in controlList)
            {
                if (c == null)
                    continue;

                if (c.IsEnabled && c.IsVisible && c.ContainsPoint(pt))
                    return c;
            }

            return null;
        }
        /// <summary>Returns the control located at this index(if one exists)</summary>
        public Control GetControl(int id)
        {
            foreach(Control c in controlList)
            {
                if (c == null)
                    continue;

                if (c.ID == id)
                    return c;
            }

            return null;
        }
        /// <summary>Returns the control located at this index of this type(if one exists)</summary>
        public Control GetControl(int id, ControlType typeControl)
        {
            foreach(Control c in controlList)
            {
                if (c == null)
                    continue;

                if ((c.ID == id) && (c.ControlType == typeControl))
                    return c;
            }

            return null;
        }

        /// <summary>Returns the static text control located at this index(if one exists)</summary>
        public StaticText GetStaticText(int id) { return GetControl(id, ControlType.StaticText) as StaticText; }
        /// <summary>Returns the button control located at this index(if one exists)</summary>
        public Button GetButton(int id) { return GetControl(id, ControlType.Button) as Button; }
        /// <summary>Returns the checkbox control located at this index(if one exists)</summary>
        public Checkbox GetCheckbox(int id) { return GetControl(id, ControlType.CheckBox) as Checkbox; }
        /// <summary>Returns the radio button control located at this index(if one exists)</summary>
        public RadioButton GetRadioButton(int id) { return GetControl(id, ControlType.RadioButton) as RadioButton; }
        /// <summary>Returns the combo box control located at this index(if one exists)</summary>
        public ComboBox GetComboBox(int id) { return GetControl(id, ControlType.ComboBox) as ComboBox; }
        /// <summary>Returns the slider control located at this index(if one exists)</summary>
        public Slider GetSlider(int id) { return GetControl(id, ControlType.Slider) as Slider; }
        /// <summary>Returns the listbox control located at this index(if one exists)</summary>
        public ListBox GetListBox(int id) { return GetControl(id, ControlType.ListBox) as ListBox; }
        #endregion

        #region Default Elements
        /// <summary>
        /// Sets the default element
        /// </summary>
        public void SetDefaultElement(ControlType ctype, uint index, Element e)
        {
            // If this element already exists, just update it
            for (int i = 0; i < defaultElementList.Count; i++)
            {
                ElementHolder holder = (ElementHolder)defaultElementList[i];
                if ( (holder.ControlType == ctype) &&
                    (holder.ElementIndex == index) )
                {
                    // Found it, update it
                    holder.Element = e.Clone();
                    defaultElementList[i] = holder;
                    return;
                }
            }

            // Couldn't find it, add a new entry
            ElementHolder newEntry = new ElementHolder();
            newEntry.ControlType = ctype;
            newEntry.ElementIndex = index;
            newEntry.Element = e.Clone();

            // Add it now
            defaultElementList.Add(newEntry);
        }
        /// <summary>
        /// Gets the default element
        /// </summary>
        public Element GetDefaultElement(ControlType ctype, uint index)
        {
            for (int i = 0; i < defaultElementList.Count; i++)
            {
                ElementHolder holder = (ElementHolder)defaultElementList[i];
                if ( (holder.ControlType == ctype) &&
                    (holder.ElementIndex == index) )
                {
                    // Found it, return it
                    return holder.Element;
                }
            }
            return null;
        }
        #endregion

        #region Texture/Font Resources
        /// <summary>
        /// Shared resource access. Indexed fonts and textures are shared among
        /// all the controls.
        /// </summary>
        public void SetFont(uint index, string faceName, uint height, FontWeight weight)
        {
            // Make sure the list is at least big enough to hold this index
            for (uint i = (uint)fontList.Count; i <= index; i++)
                fontList.Add((int)(-1));

            int fontIndex = DialogResourceManager.GetGlobalInstance().AddFont(faceName, height, weight);
            fontList[(int)index] = fontIndex;
        }
        /// <summary>
        /// Shared resource access. Indexed fonts and textures are shared among
        /// all the controls.
        /// </summary>
        public FontNode GetFont(uint index)
        {
            return DialogResourceManager.GetGlobalInstance().GetFontNode((int)fontList[(int)index]);
        }
        /// <summary>
        /// Shared resource access. Indexed fonts and textures are shared among
        /// all the controls.
        /// </summary>
        public void SetTexture(uint index, string filename)
        {
            // Make sure the list is at least big enough to hold this index
            for (uint i = (uint)textureList.Count; i <= index; i++)
                textureList.Add((int)(-1));

            int textureIndex = DialogResourceManager.GetGlobalInstance().AddTexture(filename);
            textureList[(int)index] = textureIndex;
        }
        /// <summary>
        /// Shared resource access. Indexed fonts and textures are shared among
        /// all the controls.
        /// </summary>
        public TextureNode GetTexture(uint index)
        {
            return DialogResourceManager.GetGlobalInstance().GetTextureNode((int)textureList[(int)index]);
        }
        #endregion

        #region Control Creation
        /// <summary>
        /// Initializes a control
        /// </summary>
        public void InitializeControl(Control control)
        {
            if (control == null)
                throw new ArgumentNullException("control", "You cannot pass in a null control to initialize");

            // Set the index
            control.index = (uint)controlList.Count;

            // Look for a default element entires
            for (int i = 0; i < defaultElementList.Count; i++)
            {
                // Find any elements for this control
                ElementHolder holder = (ElementHolder)defaultElementList[i];
                if (holder.ControlType == control.ControlType)
                    control[holder.ElementIndex] = holder.Element;
            }

            // Initialize the control
            control.OnInitialize();
        }
        /// <summary>
        /// Adds a control to the dialog
        /// </summary>
        public void AddControl(Control control)
        {
            // Initialize the control first
            InitializeControl(control);

            // Add this to the control list
            controlList.Add(control);
        }
        /// <summary>Adds a static text control to the dialog</summary>
        public StaticText AddStatic(int id, string text, int x, int y, int w, int h, bool isDefault)
        {
            // First create the static
            StaticText s = new StaticText(this);

            // Now call the add control method
            AddControl(s);

            // Set the properties of the static now
            s.ID = id;
            s.SetText(text);
            s.SetLocation(x, y);
            s.SetSize(w,h);
            s.isDefault = isDefault;

            return s;
        }
        /// <summary>Adds a static text control to the dialog</summary>
        public StaticText AddStatic(int id, string text, int x, int y, int w, int h){return AddStatic(id, text, x, y, w, h, false); }
        /// <summary>Adds a button control to the dialog</summary>
        public Button AddButton(int id, string text, int x, int y, int w, int h, System.Windows.Forms.Keys hotkey, bool isDefault)
        {
            // First create the button
            Button b = new Button(this);

            // Now call the add control method
            AddControl(b);

            // Set the properties of the button now
            b.ID = id;
            b.SetText(text);
            b.SetLocation(x, y);
            b.SetSize(w,h);
            b.Hotkey = hotkey;
            b.isDefault = isDefault;

            return b;
        }
        /// <summary>Adds a button control to the dialog</summary>
        public Button AddButton(int id, string text, int x, int y, int w, int h) { return AddButton(id, text, x, y, w, h, 0, false); }
        /// <summary>Adds a checkbox to the dialog</summary>
        public Checkbox AddCheckBox(int id, string text, int x, int y, int w, int h, bool ischecked, System.Windows.Forms.Keys hotkey, bool isDefault)
        {
            // First create the checkbox
            Checkbox c = new Checkbox(this);

            // Now call the add control method
            AddControl(c);

            // Set the properties of the button now
            c.ID = id;
            c.SetText(text);
            c.SetLocation(x, y);
            c.SetSize(w,h);
            c.Hotkey = hotkey;
            c.isDefault = isDefault;
            c.IsChecked = ischecked;

            return c;
        }
        /// <summary>Adds a checkbox control to the dialog</summary>
        public Checkbox AddCheckBox(int id, string text, int x, int y, int w, int h, bool ischecked) { return AddCheckBox(id, text, x, y, w, h, ischecked, 0, false); }
        /// <summary>Adds a radiobutton to the dialog</summary>
        public RadioButton AddRadioButton(int id, uint groupId, string text, int x, int y, int w, int h, bool ischecked, System.Windows.Forms.Keys hotkey, bool isDefault)
        {
            // First create the RadioButton
            RadioButton c = new RadioButton(this);

            // Now call the add control method
            AddControl(c);

            // Set the properties of the button now
            c.ID = id;
            c.ButtonGroup = groupId;
            c.SetText(text);
            c.SetLocation(x, y);
            c.SetSize(w,h);
            c.Hotkey = hotkey;
            c.isDefault = isDefault;
            c.IsChecked = ischecked;

            return c;
        }
        /// <summary>Adds a radio button control to the dialog</summary>
        public RadioButton AddRadioButton(int id, uint groupId, string text, int x, int y, int w, int h, bool ischecked) { return AddRadioButton(id, groupId, text, x, y, w, h, ischecked, 0, false); }
        /// <summary>Adds a combobox control to the dialog</summary>
        public ComboBox AddComboBox(int id, int x, int y, int w, int h, System.Windows.Forms.Keys hotkey, bool isDefault)
        {
            // First create the combo
            ComboBox c = new ComboBox(this);

            // Now call the add control method
            AddControl(c);

            // Set the properties of the button now
            c.ID = id;
            c.SetLocation(x, y);
            c.SetSize(w,h);
            c.Hotkey = hotkey;
            c.isDefault = isDefault;

            return c;
        }
        /// <summary>Adds a combobox control to the dialog</summary>
        public ComboBox AddComboBox(int id, int x, int y, int w, int h) { return AddComboBox(id, x, y, w, h, 0, false); }
        /// <summary>Adds a slider control to the dialog</summary>
        public Slider AddSlider(int id, int x, int y, int w, int h, int min, int max, int initialValue, bool isDefault)
        {
            // First create the slider
            Slider c = new Slider(this);

            // Now call the add control method
            AddControl(c);

            // Set the properties of the button now
            c.ID = id;
            c.SetLocation(x, y);
            c.SetSize(w,h);
            c.isDefault = isDefault;
            c.SetRange(min, max);
            c.Value = initialValue;

            return c;
        }
        /// <summary>Adds a slider control to the dialog</summary>
        public Slider AddSlider(int id, int x, int y, int w, int h) { return AddSlider(id, x, y, w, h, 0,100,50, false); }
        /// <summary>Adds a listbox control to the dialog</summary>
        public ListBox AddListBox(int id, int x, int y, int w, int h, ListBoxStyle style)
        {
            // First create the listbox
            ListBox c = new ListBox(this);

            // Now call the add control method
            AddControl(c);

            // Set the properties of the button now
            c.ID = id;
            c.SetLocation(x, y);
            c.SetSize(w,h);
            c.Style = style;

            return c;
        }
        /// <summary>Adds a listbox control to the dialog</summary>
        public ListBox AddListBox(int id, int x, int y, int w, int h) { return AddListBox(id, x, y, w, h, ListBoxStyle.SingleSelection); }
        /// <summary>Adds an edit box control to the dialog</summary>
        public EditBox AddEditBox(int id, string text, int x, int y, int w, int h, bool isDefault)
        {
            // First create the editbox
            EditBox c = new EditBox(this);

            // Now call the add control method
            AddControl(c);

            // Set the properties of the static now
            c.ID = id;
            c.Text = (text != null) ? text : string.Empty;
            c.SetLocation(x, y);
            c.SetSize(w,h);
            c.isDefault = isDefault;

            return c;
        }
        /// <summary>Adds an edit box control to the dialog</summary>
        public EditBox AddEditBox(int id, string text, int x, int y, int w, int h){return AddEditBox(id, text, x, y, w, h, false); }
        #endregion

        /// <summary>Render the dialog</summary>
        private void UpdateVertices()
        {
            vertices = new Microsoft.DirectX.Direct3D.CustomVertex.TransformedColoredTextured[] {
                new CustomVertex.TransformedColoredTextured(dialogX,dialogY,0.5f,1.0f,topLeftColor.ToArgb(),0.0f,0.5f),
                new CustomVertex.TransformedColoredTextured(dialogX + width,dialogY,0.5f,1.0f,topRightColor.ToArgb(),1.0f,0.5f),
                new CustomVertex.TransformedColoredTextured(dialogX+width,dialogY+height,0.5f,1.0f,bottomRightColor.ToArgb(),1.0f,1.0f),
                new CustomVertex.TransformedColoredTextured(dialogX,dialogY+height,0.5f,1.0f,bottomLeftColor.ToArgb(),0.0f,1.0f)
            };
        }
        #region Drawing methods
        /// <summary>Render the dialog</summary>
        public void OnRender(float elapsedTime)
        {
            // See if the dialog needs to be refreshed
            if (timeLastRefresh < timeRefresh)
            {
                timeLastRefresh = FrameworkTimer.GetTime();
                Refresh();
            }

            Device device = DialogResourceManager.GetGlobalInstance().Device;

            // Set up a state block here and restore it when finished drawing all the controls
            DialogResourceManager.GetGlobalInstance().StateBlock.Capture();

            // Set some render/texture states
            device.RenderState.AlphaBlendEnable = true;
            device.RenderState.SourceBlend = Blend.SourceAlpha;
            device.RenderState.DestinationBlend = Blend.InvSourceAlpha;
            device.RenderState.AlphaTestEnable = false;
            device.TextureState[0].ColorOperation = TextureOperation.SelectArg2;
            device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
            device.TextureState[0].AlphaOperation = TextureOperation.SelectArg1;
            device.TextureState[0].AlphaArgument1 = TextureArgument.Diffuse;
            device.RenderState.ZBufferEnable = false;
            // Clear vertex/pixel shader
            device.VertexShader = null;
            device.PixelShader = null;

            // Render if not minimized
            if (!isDialogMinimized)
            {
                device.VertexFormat = CustomVertex.TransformedColoredTextured.Format;
                device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vertices);
            }

            // Reset states
            device.TextureState[0].ColorOperation = TextureOperation.Modulate;
            device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
            device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
            device.TextureState[0].AlphaOperation = TextureOperation.Modulate;
            device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
            device.TextureState[0].AlphaArgument2 = TextureArgument.Diffuse;

            device.SamplerState[0].MinFilter = TextureFilter.Linear;

            // Set the texture up, and begin the sprite
            TextureNode tNode = GetTexture(0);
            device.SetTexture(0, tNode.Texture);
            DialogResourceManager.GetGlobalInstance().Sprite.Begin(SpriteFlags.DoNotSaveState);

            // Render the caption if it's enabled.
            if (hasCaption)
            {
                // DrawSprite will offset the rect down by
                // captionHeight, so adjust the rect higher
                // here to negate the effect.
                System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0,-captionHeight,width,0);
                DrawSprite(captionElement, rect);
                rect.Offset(5, 0); // Make a left margin
                string output = caption + ((isDialogMinimized) ? " (Minimized)" : null);
                DrawText(output, captionElement, rect, true);
            }

            // If the dialog is minimized, skip rendering
            // its controls.
            if (!isDialogMinimized)
            {
                for(int i = 0; i < controlList.Count; i++)
                {
                    // Focused control is drawn last
                    if (controlList[i] == controlFocus)
                        continue;

                    (controlList[i] as Control).Render(device, elapsedTime);
                }

                // Render the focus control if necessary
                if (controlFocus != null && controlFocus.Parent == this)
                    controlFocus.Render(device, elapsedTime);
            }

            // End the sprite and apply the stateblock
            DialogResourceManager.GetGlobalInstance().Sprite.End();
            DialogResourceManager.GetGlobalInstance().StateBlock.Apply();
        }

        /// <summary>
        /// Refresh the dialog
        /// </summary>
        private void Refresh()
        {
            // Reset the controls
            if (controlFocus != null)
                controlFocus.OnFocusOut();

            if (controlMouseOver != null)
                controlMouseOver.OnMouseExit();

            controlFocus = null;
            controlMouseDown = null;
            controlMouseOver = null;

            // Refresh any controls
            foreach(Control c in controlList)
            {
                c.Refresh();
            }

            if (usingKeyboardInput)
                FocusDefaultControl();
        }

        /// <summary>Draw's some text</summary>
        public void DrawText(string text, Element element, System.Drawing.Rectangle rect, bool shadow)
        {
            // No need to draw fully transparant layers
            if (element.FontColor.Current.Alpha == 0)
                return; // Nothing to do

            System.Drawing.Rectangle screenRect = rect;
            screenRect.Offset(dialogX, dialogY);

            // If caption is enabled, offset the Y position by its height.
            if (hasCaption)
                screenRect.Offset(0, captionHeight);

            // Set the identity transform
            DialogResourceManager.GetGlobalInstance().Sprite.Transform = Matrix.Identity;

            // Get the font node here
            FontNode fNode = GetFont(element.FontIndex);
            if (shadow)
            {
                // Render the text shadowed
                System.Drawing.Rectangle shadowRect = screenRect;
                shadowRect.Offset(1, 1);
                fNode.Font.DrawText(DialogResourceManager.GetGlobalInstance().Sprite, text,
                    shadowRect, element.textFormat, unchecked((int)0xff000000));
            }

            fNode.Font.DrawText(DialogResourceManager.GetGlobalInstance().Sprite, text,
                screenRect, element.textFormat, element.FontColor.Current.ToArgb());
        }
        /// <summary>Draw a sprite</summary>
        public void DrawSprite(Element element, System.Drawing.Rectangle rect)
        {
            // No need to draw fully transparant layers
            if (element.TextureColor.Current.Alpha == 0)
                return; // Nothing to do

            System.Drawing.Rectangle texRect = element.textureRect;
            System.Drawing.Rectangle screenRect = rect;
            screenRect.Offset(dialogX, dialogY);

            // If caption is enabled, offset the Y position by its height.
            if (hasCaption)
                screenRect.Offset(0, captionHeight);

            // Get the texture
            TextureNode tNode = GetTexture(element.TextureIndex);
            float scaleX = (float)screenRect.Width / (float)texRect.Width;
            float scaleY = (float)screenRect.Height / (float)texRect.Height;

            // Set the scaling transform
            DialogResourceManager.GetGlobalInstance().Sprite.Transform = Matrix.Scaling(scaleX, scaleY, 1.0f);
            
            // Calculate the position
            Vector3 pos = new Vector3(screenRect.Left, screenRect.Top, 0.0f);
            pos.X /= scaleX;
            pos.Y /= scaleY;

            // Finally draw the sprite
            DialogResourceManager.GetGlobalInstance().Sprite.Draw(tNode.Texture, texRect, new Vector3(), pos, element.TextureColor.Current.ToArgb()); 
        }
        /// <summary>Draw's some text</summary>
        public void DrawText(string text, Element element, System.Drawing.Rectangle rect) { this.DrawText(text, element, rect, false); }
        /// <summary>Draw a rectangle</summary>
        public void DrawRectangle(System.Drawing.Rectangle rect, ColorValue color)
        {
            // Offset the rectangle
            rect.Offset(dialogX, dialogY);

            // If caption is enabled, offset the Y position by its height
            if (hasCaption)
                rect.Offset(0, captionHeight);

            // Get the integer value of the color
            int realColor = color.ToArgb();
            // Create some vertices
            CustomVertex.TransformedColoredTextured[] verts = {
                new CustomVertex.TransformedColoredTextured((float)rect.Left - 0.5f, (float)rect.Top -0.5f, 0.5f, 1.0f, realColor, 0, 0),
                new CustomVertex.TransformedColoredTextured((float)rect.Right - 0.5f, (float)rect.Top -0.5f, 0.5f, 1.0f, realColor, 0, 0),
                new CustomVertex.TransformedColoredTextured((float)rect.Right - 0.5f, (float)rect.Bottom -0.5f, 0.5f, 1.0f, realColor, 0, 0),
                new CustomVertex.TransformedColoredTextured((float)rect.Left - 0.5f, (float)rect.Bottom -0.5f, 0.5f, 1.0f, realColor, 0, 0),
            };

            // Get the device
            Device device = SampleFramework.Device;

            // Since we're doing our own drawing here, we need to flush the sprites
            DialogResourceManager.GetGlobalInstance().Sprite.Flush();
            // Preserve the devices current vertex declaration
            using (VertexDeclaration decl = device.VertexDeclaration)
            {
                // Set the vertex format
                device.VertexFormat = CustomVertex.TransformedColoredTextured.Format;

                // Set some texture states
                device.TextureState[0].ColorOperation = TextureOperation.SelectArg2;
                device.TextureState[0].AlphaOperation = TextureOperation.SelectArg2;

                // Draw the rectangle
                device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, verts);

                // Reset some texture states
                device.TextureState[0].ColorOperation = TextureOperation.Modulate;
                device.TextureState[0].AlphaOperation = TextureOperation.Modulate;

                // Restore the vertex declaration
                device.VertexDeclaration = decl;
            }
        }
        #endregion

    }

    #region Abstract Control class
    /// <summary>Base class for all controls</summary>
    public abstract class Control
    {
        #region Instance data
        protected Dialog parentDialog; // Parent container
        public uint index; // Index within the control list
        public bool isDefault;

        // Protected members
        protected object localUserData; // User specificied data
        protected bool visible;
        protected bool isMouseOver;
        protected bool hasFocus;
        protected int controlId; // ID Number
        protected ControlType controlType; // Control type, set in constructor
        protected System.Windows.Forms.Keys hotKey; // Controls hotkey
        protected bool enabled; // Enabled/disabled flag
        protected System.Drawing.Rectangle boundingBox; // Rectangle defining the active region of the control

        protected int controlX,controlY,width,height; // Size, scale, and positioning members

        protected ArrayList elementList = new ArrayList(); // All display elements
        #endregion

        /// <summary>Initialize the control</summary>
        public virtual void OnInitialize() {} // Nothing to do here
        /// <summary>Render the control</summary>
        public virtual void Render(Device device, float elapsedTime) {} // Nothing to do here
        /// <summary>Message Handler</summary>
        public virtual bool MsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam) {return false;} // Nothing to do here
        /// <summary>Handle the keyboard data</summary>
        public virtual bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam) {return false;} // Nothing to do here
        /// <summary>Handle the mouse data</summary>
        public virtual bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam) {return false;} // Nothing to do here

        /// <summary>User specified data</summary>
        public object UserData { get { return localUserData; } set { localUserData = value; } }
        /// <summary>The parent dialog of this control</summary>
        public Dialog Parent { get { return parentDialog; } }
        /// <summary>Can the control have focus</summary>
        public virtual bool CanHaveFocus { get { return false; } }
        /// <summary>Called when control gets focus</summary>
        public virtual void OnFocusIn() { hasFocus = true;}
        /// <summary>Called when control loses focus</summary>
        public virtual void OnFocusOut() { hasFocus = false;}
        /// <summary>Called when mouse goes over the control</summary>
        public virtual void OnMouseEnter() { isMouseOver = true;}
        /// <summary>Called when mouse leaves the control</summary>
        public virtual void OnMouseExit() { isMouseOver = false;}
        /// <summary>Called when the control's hotkey is hit</summary>
        public virtual void OnHotKey() {} // Nothing to do here
        /// <summary>Does the control contain this point</summary>
        public virtual bool ContainsPoint(System.Drawing.Point pt) { return boundingBox.Contains(pt); }
        /// <summary>Is the control enabled</summary>
        public virtual bool IsEnabled { get { return enabled; } set { enabled = value; } }
        /// <summary>Is the control visible</summary>
        public virtual bool IsVisible { get { return visible; } set { visible = value; } }
        /// <summary>Type of the control</summary>
        public virtual ControlType ControlType { get { return controlType; } }
        /// <summary>Unique ID of the control</summary>
        public virtual int ID { get { return controlId; } set { controlId = value; } }
        /// <summary>Called to set control's location</summary>
        public virtual void SetLocation(int x, int y) { controlX = x; controlY = y; UpdateRectangles(); }
        /// <summary>Called to set control's size</summary>
        public virtual void SetSize(int w, int h) { width = w; height = h; UpdateRectangles(); }
        /// <summary>The controls hotkey</summary>
        public virtual System.Windows.Forms.Keys Hotkey { get { return hotKey; } set { hotKey = value; } }

        /// <summary>
        /// Index for the elements this control has access to
        /// </summary>
        public Element this[uint index]
        {
            get { return elementList[(int)index] as Element; }
            set 
            { 
                if (value == null)
                    throw new ArgumentNullException("ControlIndexer", "You cannot set a null element.");
                
                // Is the collection big enough?
                for(uint i = (uint)elementList.Count; i <= index; i++)
                {
                    // Add a new one
                    elementList.Add(new Element());
                }
                // Update the data (with a clone)
                elementList[(int)index] = value.Clone();
            }
        }
        /// <summary>
        /// Create a new instance of a control
        /// </summary>
        protected Control(Dialog parent)
        {
            controlType = ControlType.Button;
            parentDialog = parent;
            controlId = 0;
            index = 0;

            enabled = true;
            visible = true;
            isMouseOver = false;
            hasFocus = false;
            isDefault = false;

            controlX = 0; controlY = 0; width = 0; height = 0;
        }

        /// <summary>
        /// Refreshes the control
        /// </summary>
        public virtual void Refresh()
        {
            isMouseOver = false;
            hasFocus = false;
            for(int i = 0; i < elementList.Count; i++)
            {
                (elementList[i] as Element).Refresh();
            }
        }

        /// <summary>
        /// Updates the rectangles
        /// </summary>
        protected virtual void UpdateRectangles()
        {
            boundingBox = new System.Drawing.Rectangle(controlX, controlY, width, height);
        }
    }
    #endregion

    #region StaticText control
    /// <summary>
    /// StaticText text control
    /// </summary>
    public class StaticText : Control
    {
        public const int TextElement = 0;
        protected string textData; // Window text

        /// <summary>
        /// Create a new instance of a static text control
        /// </summary>
        public StaticText(Dialog parent) : base(parent)
        {
            controlType = ControlType.StaticText;
            parentDialog = parent;
            textData = string.Empty;
            elementList.Clear();
        }

        /// <summary>
        /// Render this control
        /// </summary>
        public override void Render(Device device, float elapsedTime)
        {
            if (!IsVisible)
                return; // Nothing to do here

            ControlState state = ControlState.Normal;
            if (!IsEnabled)
                state = ControlState.Disabled;

            // Blend the element colors
            Element e = elementList[TextElement] as Element;
            e.FontColor.Blend(state, elapsedTime);

            // Render with a shadow
            parentDialog.DrawText(textData, e, boundingBox, true);
        }

        /// <summary>
        /// Return a copy of the string
        /// </summary>
        public string GetTextCopy()
        {
            return string.Copy(textData);
        }

        /// <summary>
        /// Sets the updated text for this control
        /// </summary>
        public void SetText(string newText)
        {
            textData = newText;
        }

    }
    #endregion

    #region Button control

    /// <summary>
    /// Button control
    /// </summary>
    public class Button : StaticText
    {
        public const int ButtonLayer = 0;
        public const int FillLayer = 1;
        protected bool isPressed;
        #region Event code
        public event EventHandler Click;
        /// <summary>Create new button instance</summary>
        protected void RaiseClickEvent(Button sender, bool wasTriggeredByUser)
        {
            // Discard events triggered programatically if these types of events haven't been
            // enabled
            if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
                return;

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

        /// <summary>Create new button instance</summary>
        public Button(Dialog parent) : base(parent)
        {
            controlType = ControlType.Button;
            parentDialog = parent;
            isPressed = false;
            hotKey = 0;
        }

        /// <summary>Can the button have focus</summary>
        public override bool CanHaveFocus { get { return IsVisible && IsEnabled; } }
        /// <summary>The hotkey for this button was pressed</summary>
        public override void OnHotKey()
        {
            RaiseClickEvent(this, true);
        }

        /// <summary>
        /// Will handle the keyboard strokes
        /// </summary>
        public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            switch(msg)
            {
                case NativeMethods.WindowMessage.KeyDown:
                    if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
                    {
                        isPressed = true;
                        return true;
                    }
                    break;
                case NativeMethods.WindowMessage.KeyUp:
                    if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
                    {
                        isPressed = false;
                        RaiseClickEvent(this, true);

                        return true;
                    }
                    break;
            }
            return false;
        }

        /// <summary>
        /// Handle mouse messages from the buttons
        /// </summary>
        public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            switch(msg)
            {
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                case NativeMethods.WindowMessage.LeftButtonDown:
                {
                    if (ContainsPoint(pt))
                    {
                        // Pressed while inside the control
                        isPressed = true;
                        Parent.SampleFramework.Window.Capture = true;
                        if (!hasFocus)
                            Dialog.RequestFocus(this);

                        return true;
                    }
                }
                    break;
                case NativeMethods.WindowMessage.LeftButtonUp:
                {
                    if (isPressed)
                    {
                        isPressed = false;
                        Parent.SampleFramework.Window.Capture = false;
                        if (!parentDialog.IsUsingKeyboardInput)
                            Dialog.ClearFocus();

                        // Button click
                        if (ContainsPoint(pt))
                            RaiseClickEvent(this, true);
                    }
                }
                    break;
            }

            return false;
        }

        /// <summary>Render the button</summary>
        public override void Render(Device device, float elapsedTime)
        {
            int offsetX = 0;
            int offsetY = 0;

            ControlState state = ControlState.Normal;
            if (IsVisible == false)
            {
                state = ControlState.Hidden;
            }
            else if (IsEnabled == false)
            {
                state = ControlState.Disabled;
            }
            else if (isPressed)
            {
                state = ControlState.Pressed;
                offsetX = 1;
                offsetY = 2;
            }
            else if (isMouseOver)
            {
                state = ControlState.MouseOver;
                offsetX = -1;
                offsetY = -2;
            }
            else if (hasFocus)
            {
                state = ControlState.Focus;
            }

            // Background fill layer
            Element e = elementList[Button.ButtonLayer] as Element;
            float blendRate = (state == ControlState.Pressed) ? 0.0f : 0.8f;
            
            System.Drawing.Rectangle buttonRect = boundingBox;
            buttonRect.Offset(offsetX, offsetY);
            
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            e.FontColor.Blend(state, elapsedTime, blendRate);

            // Draw sprite/text of button
            parentDialog.DrawSprite(e, buttonRect);
            parentDialog.DrawText(textData, e, buttonRect);

            // Main button
            e = elementList[Button.FillLayer] as Element;
            
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            e.FontColor.Blend(state, elapsedTime, blendRate);

            parentDialog.DrawSprite(e, buttonRect);
            parentDialog.DrawText(textData, e, buttonRect);
        }

    }
    #endregion

    #region Checkbox Control
    /// <summary>
    /// Checkbox control
    /// </summary>
    public class Checkbox : Button
    {
        public const int BoxLayer = 0;
        public const int CheckLayer = 1;
        #region Event code
        public event EventHandler Changed;
        /// <summary>Create new button instance</summary>
        protected void RaiseChangedEvent(Checkbox sender, bool wasTriggeredByUser)
        {
            // Discard events triggered programatically if these types of events haven't been
            // enabled
            if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
                return;

            // Fire both the changed and clicked event
            base.RaiseClickEvent(sender, wasTriggeredByUser);
            if (Changed != null)
                Changed(sender, EventArgs.Empty);
        }
        #endregion
        protected System.Drawing.Rectangle buttonRect;
        protected System.Drawing.Rectangle textRect;
        protected bool isBoxChecked;

        /// <summary>
        /// Create new checkbox instance
        /// </summary>
        public Checkbox(Dialog parent) : base(parent)
        {
            controlType = ControlType.CheckBox;
            isBoxChecked = false;
            parentDialog = parent;
        }

        /// <summary>
        /// Checked property
        /// </summary>
        public virtual bool IsChecked
        {
            get { return isBoxChecked; }
            set { SetCheckedInternal(value, false); }
        }
        /// <summary>
        /// Sets the checked state and fires the event if necessary
        /// </summary>
        protected virtual void SetCheckedInternal(bool ischecked, bool fromInput)
        {
            isBoxChecked = ischecked;
            RaiseChangedEvent(this, fromInput);
        }

        /// <summary>
        /// Override hotkey to fire event
        /// </summary>
        public override void OnHotKey()
        {
            SetCheckedInternal(!isBoxChecked, true);
        }

        /// <summary>
        /// Does the control contain the point?
        /// </summary>
        public override bool ContainsPoint(System.Drawing.Point pt)
        {
            return (boundingBox.Contains(pt) || buttonRect.Contains(pt));
        }
        /// <summary>
        /// Update the rectangles
        /// </summary>
        protected override void UpdateRectangles()
        {
            // Update base first
            base.UpdateRectangles();

            // Update the two rects
            buttonRect = boundingBox;
            buttonRect = new System.Drawing.Rectangle(boundingBox.Location,
                new System.Drawing.Size(boundingBox.Height, boundingBox.Height));

            textRect = boundingBox;
            textRect.Offset((int) (1.25f * buttonRect.Width), 0);
        }

        /// <summary>
        /// Render the checkbox control
        /// </summary>
        public override void Render(Device device, float elapsedTime)
        {
            ControlState state = ControlState.Normal;
            if (IsVisible == false)
                state = ControlState.Hidden;
            else if (IsEnabled == false)
                state = ControlState.Disabled;
            else if (isPressed)
                state = ControlState.Pressed;
            else if (isMouseOver)
                state = ControlState.MouseOver;
            else if (hasFocus)
                state = ControlState.Focus;
 
            Element e = elementList[Checkbox.BoxLayer] as Element;
            float blendRate = (state == ControlState.Pressed) ? 0.0f : 0.8f;
            
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            e.FontColor.Blend(state, elapsedTime, blendRate);

            // Draw sprite/text of checkbox
            parentDialog.DrawSprite(e, buttonRect);
            parentDialog.DrawText(textData, e, textRect);

            if (!isBoxChecked)
                state = ControlState.Hidden;

            e = elementList[Checkbox.CheckLayer] as Element;
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);

            // Draw sprite of checkbox
            parentDialog.DrawSprite(e, buttonRect);
        }

        /// <summary>
        /// Handle the keyboard for the checkbox
        /// </summary>
        public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            switch(msg)
            {
                case NativeMethods.WindowMessage.KeyDown:
                    if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
                    {
                        isPressed = true;
                        return true;
                    }
                    break;
                case NativeMethods.WindowMessage.KeyUp:
                    if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
                    {
                        if (isPressed)
                        {
                            isPressed = false;
                            SetCheckedInternal(!isBoxChecked, true);
                        }
                        return true;
                    }
                    break;
            }
            return false;
        }

        /// <summary>
        /// Handle mouse messages from the checkbox
        /// </summary>
        public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            switch(msg)
            {
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                case NativeMethods.WindowMessage.LeftButtonDown:
                {
                    if (ContainsPoint(pt))
                    {
                        // Pressed while inside the control
                        isPressed = true;
                        Parent.SampleFramework.Window.Capture = true;
                        if ( (!hasFocus) && (parentDialog.IsUsingKeyboardInput) )
                            Dialog.RequestFocus(this);

                        return true;
                    }
                }
                    break;
                case NativeMethods.WindowMessage.LeftButtonUp:
                {
                    if (isPressed)
                    {
                        isPressed = false;
                        Parent.SampleFramework.Window.Capture = false;

                        // Button click
                        if (ContainsPoint(pt))
                        {
                            SetCheckedInternal(!isBoxChecked, true);
                        }
                        
                        return true;
                    }
                }
                    break;
            }

            return false;
        }
    }
    #endregion

    #region RadioButton Control
    /// <summary>
    /// Radio button control
    /// </summary>
    public class RadioButton : Checkbox
    {
        protected uint buttonGroupIndex;
        /// <summary>
        /// Create new radio button instance
        /// </summary>
        public RadioButton(Dialog parent) : base(parent)
        {
            controlType = ControlType.RadioButton;
            parentDialog = parent;
        }

        /// <summary>
        /// Button Group property
        /// </summary>
        public uint ButtonGroup
        {
            get { return buttonGroupIndex; }
            set { buttonGroupIndex = value; }
        }

        /// <summary>
        /// Sets the check state and potentially clears the group
        /// </summary>
        public void SetChecked(bool ischecked, bool clear)
        {
            SetCheckedInternal(ischecked, clear, false); 
        }

        /// <summary>
        /// Sets the checked state and fires the event if necessary
        /// </summary>
        protected virtual void SetCheckedInternal(bool ischecked, bool clearGroup, bool fromInput)
        {
            isBoxChecked = ischecked;
            RaiseChangedEvent(this, fromInput);
        }

        /// <summary>
        /// Override hotkey to fire event
        /// </summary>
        public override void OnHotKey()
        {
            SetCheckedInternal(true, true);
        }

        /// <summary>
        /// Handle the keyboard for the checkbox
        /// </summary>
        public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            switch(msg)
            {
                case NativeMethods.WindowMessage.KeyDown:
                    if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
                    {
                        isPressed = true;
                        return true;
                    }
                    break;
                case NativeMethods.WindowMessage.KeyUp:
                    if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
                    {
                        if (isPressed)
                        {
                            isPressed = false;
                            parentDialog.ClearRadioButtonGroup(buttonGroupIndex);
                            isBoxChecked = !isBoxChecked;

                            RaiseChangedEvent(this, true);
                        }
                        return true;
                    }
                    break;
            }
            return false;
        }

        /// <summary>
        /// Handle mouse messages from the radio button
        /// </summary>
        public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            switch(msg)
            {
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                case NativeMethods.WindowMessage.LeftButtonDown:
                {
                    if (ContainsPoint(pt))
                    {
                        // Pressed while inside the control
                        isPressed = true;
                        Parent.SampleFramework.Window.Capture = true;
                        if ( (!hasFocus) && (parentDialog.IsUsingKeyboardInput) )
                            Dialog.RequestFocus(this);

                        return true;
                    }
                }
                    break;
                case NativeMethods.WindowMessage.LeftButtonUp:
                {
                    if (isPressed)
                    {
                        isPressed = false;
                        Parent.SampleFramework.Window.Capture = false;

                        // Button click
                        if (ContainsPoint(pt))
                        {
                            parentDialog.ClearRadioButtonGroup(buttonGroupIndex);
                            isBoxChecked = !isBoxChecked;

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

            return false;
        }
    }
    #endregion

    #region Scrollbar control
    /// <summary>
    /// A scroll bar control
    /// </summary>
    public class ScrollBar : Control
    {
        public const int TrackLayer = 0;
        public const int UpButtonLayer = 1;
        public const int DownButtonLayer = 2;
        public const int ThumbLayer = 3;
        protected const int MinimumThumbSize = 8;
        #region Instance Data
        protected bool showingThumb;
        protected System.Drawing.Rectangle upButtonRect;
        protected System.Drawing.Rectangle downButtonRect;
        protected System.Drawing.Rectangle trackRect;
        protected System.Drawing.Rectangle thumbRect;
        protected int position; // Position of the first displayed item
        protected int pageSize; // How many items are displayable in one page
        protected int start; // First item
        protected int end; // The index after the last item
        private int thumbOffsetY;
        private bool isDragging;
        #endregion

        /// <summary>
        /// Creates a new instance of the scroll bar class
        /// </summary>
        public ScrollBar(Dialog parent) : base(parent)
        {
            // Store parent and control type
            controlType = ControlType.Scrollbar;
            parentDialog = parent;

            // Set default properties
            showingThumb = true;
            upButtonRect = System.Drawing.Rectangle.Empty;
            downButtonRect = System.Drawing.Rectangle.Empty;
            trackRect = System.Drawing.Rectangle.Empty;
            thumbRect = System.Drawing.Rectangle.Empty;

            position = 0;
            pageSize = 1;
            start = 0;
            end = 1;
        }

        /// <summary>
        /// Update all of the rectangles
        /// </summary>
        protected override void UpdateRectangles()
        {
            // Get the bounding box first
            base.UpdateRectangles();

            // Make sure buttons are square
            upButtonRect = new System.Drawing.Rectangle(boundingBox.Location,
                new System.Drawing.Size(boundingBox.Width, boundingBox.Width));

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

            trackRect = new System.Drawing.Rectangle(upButtonRect.Left, upButtonRect.Bottom, 
                upButtonRect.Width, downButtonRect.Top - upButtonRect.Bottom);

            thumbRect = upButtonRect;

            UpdateThumbRectangle();
        }

        /// <summary>
        /// Position of the track
        /// </summary>
        public int TrackPosition
        {
            get { return position; }
            set { position = value; Cap(); UpdateThumbRectangle(); }
        }
        /// <summary>
        /// Size of a 'page'
        /// </summary>
        public int PageSize
        {
            get { return pageSize; }
            set { pageSize = value; Cap(); UpdateThumbRectangle(); }
        }

        /// <summary>Clips position at boundaries</summary>
        protected void Cap()
        {
            if (position < start || end - start <= pageSize)
            {
                position = start;
            }
            else if (position + pageSize > end)
                position = end - pageSize;
        }

        /// <summary>Compute the dimension of the scroll thumb</summary>
        protected void UpdateThumbRectangle()
        {
            if (end - start > pageSize)
            {
                int thumbHeight = Math.Max(trackRect.Height * pageSize / (end-start), MinimumThumbSize);
                int maxPosition = end - start - pageSize;
                thumbRect.Location = new System.Drawing.Point(thumbRect.Left,
                    trackRect.Top + (position - start) * (trackRect.Height - thumbHeight) / maxPosition);
                thumbRect.Size = new System.Drawing.Size(thumbRect.Width, thumbHeight);
                showingThumb = true;
            }
            else
            {
                // No content to scroll
                thumbRect.Height = 0;
                showingThumb = false;
            }
        }

        /// <summary>Scrolls by delta items.  A positive value scrolls down, while a negative scrolls down</summary>
        public void Scroll(int delta)
        {
            // Perform scroll
            position += delta;
            // Cap position
            Cap();
            // Update thumb rectangle
            UpdateThumbRectangle();
        }

        /// <summary>Shows an item</summary>
        public void ShowItem(int index)
        {
            // Cap the index
            if (index < 0)
                index = 0;

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

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

            // Update thumbs again
            UpdateThumbRectangle();
        }

        /// <summary>Sets the track range</summary>
        public void SetTrackRange(int startRange, int endRange)
        {
            start = startRange; end = endRange;
            Cap();
            UpdateThumbRectangle();
        }

        /// <summary>Render the scroll bar control</summary>
        public override void Render(Device device, float elapsedTime)
        {
            ControlState state = ControlState.Normal;
            if (IsVisible == false)
                state = ControlState.Hidden;
            else if ( (IsEnabled == false) || (showingThumb == false) )
                state = ControlState.Disabled;
            else if (isMouseOver)
                state = ControlState.MouseOver;
            else if (hasFocus)
                state = ControlState.Focus;

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

            // Background track layer
            Element e = elementList[ScrollBar.TrackLayer] as Element;
            
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            parentDialog.DrawSprite(e, trackRect);

            // Up arrow
            e = elementList[ScrollBar.UpButtonLayer] as Element;
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            parentDialog.DrawSprite(e, upButtonRect);

            // Down arrow
            e = elementList[ScrollBar.DownButtonLayer] as Element;
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            parentDialog.DrawSprite(e, downButtonRect);

            // Thumb button
            e = elementList[ScrollBar.ThumbLayer] as Element;
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            parentDialog.DrawSprite(e, thumbRect);
        }

        /// <summary>Stores data for a combo box item</summary>
        public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            switch(msg)
            {
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                case NativeMethods.WindowMessage.LeftButtonDown:
                {
                    Parent.SampleFramework.Window.Capture = true;

                    // Check for on up button
                    if (upButtonRect.Contains(pt))
                    {
                        if (position > start)
                            --position;
                        UpdateThumbRectangle();
                        return true;
                    }

                    // Check for on down button
                    if (downButtonRect.Contains(pt))
                    {
                        if (position + pageSize < end)
                            ++position;
                        UpdateThumbRectangle();
                        return true;
                    }

                    // Check for click on thumb
                    if (thumbRect.Contains(pt))
                    {
                        isDragging = true;
                        thumbOffsetY = pt.Y - thumbRect.Top;
                        return true;
                    }

                    // check for click on track
                    if (thumbRect.Left <= pt.X &&
                        thumbRect.Right > pt.X)
                    {
                        if (thumbRect.Top > pt.Y &&
                            trackRect.Top <= pt.Y)
                        {
                            Scroll(-(pageSize-1));
                            return true;
                        }
                        else if (thumbRect.Bottom <= pt.Y &&
                            trackRect.Bottom > pt.Y)
                        {
                            Scroll(pageSize-1);
                            return true;
                        }
                    }

                    break;
                }
                case NativeMethods.WindowMessage.LeftButtonUp:
                {
                    isDragging = false;
                    Parent.SampleFramework.Window.Capture = false;
                    UpdateThumbRectangle();
                    break;
                }

                case NativeMethods.WindowMessage.MouseMove:
                {
                    if (isDragging)
                    {
                        // Calculate new bottom and top of thumb rect
                        int bottom = thumbRect.Bottom + (pt.Y - thumbOffsetY - thumbRect.Top);
                        int top = pt.Y - thumbOffsetY;
                        thumbRect = new System.Drawing.Rectangle(thumbRect.Left, top, thumbRect.Width, bottom - top);
                        if (thumbRect.Top < trackRect.Top)
                            thumbRect.Offset(0, trackRect.Top - thumbRect.Top);
                        else if (thumbRect.Bottom > trackRect.Bottom)
                            thumbRect.Offset(0, trackRect.Bottom - thumbRect.Bottom);

                        // Compute first item index based on thumb position
                        int maxFirstItem = end - start - pageSize; // Largest possible index for first item
                        int maxThumb = trackRect.Height - thumbRect.Height; // Largest possible thumb position

                        position = start + (thumbRect.Top - trackRect.Top +
                            maxThumb / (maxFirstItem * 2) ) * // Shift by half a row to avoid last row covered
                            maxFirstItem / maxThumb;

                        return true;
                    }
                    break;
                }
            }

            // Was not handled
            return false;
        }

    }
    #endregion

    #region ComboBox Control
    /// <summary>Stores data for a combo box item</summary>
    public struct ComboBoxItem
    {
        public string ItemText;
        public object ItemData;
        public System.Drawing.Rectangle ItemRect;
        public bool IsItemVisible;
    }

    /// <summary>Combo box control</summary>
    public class ComboBox : Button
    {
        public const int MainLayer = 0;
        public const int ComboButtonLayer = 1;
        public const int DropdownLayer = 2;
        public const int SelectionLayer = 3;
        #region Event code
        public event EventHandler Changed;
        /// <summary>Create new button instance</summary>
        protected void RaiseChangedEvent(ComboBox sender, bool wasTriggeredByUser)
        {
            // Discard events triggered programatically if these types of events haven't been
            // enabled
            if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
                return;

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

        #region Instance data
        protected int selectedIndex;
        protected int focusedIndex;
        protected int dropHeight;
        protected ScrollBar scrollbarControl;
        protected int scrollWidth;
        protected bool isComboOpen;
        protected System.Drawing.Rectangle textRect;
        protected System.Drawing.Rectangle buttonRect;
        protected System.Drawing.Rectangle dropDownRect;
        protected System.Drawing.Rectangle dropDownTextRect;
        protected ArrayList itemList;
        #endregion

        /// <summary>Create new combo box control</summary>
        public ComboBox(Dialog parent) : base(parent)
        {
            // Store control type and parent dialog
            controlType = ControlType.ComboBox;
            parentDialog = parent;
            // Create the scrollbar control too
            scrollbarControl = new ScrollBar(parent);

            // Set some default items
            dropHeight = 100;
            scrollWidth = 16;
            selectedIndex = -1;
            focusedIndex = -1;
            isScrollBarInit = false;

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

        /// <summary>Update the rectangles for the combo box control</summary>
        protected override void UpdateRectangles()
        {
            // Get bounding box
            base.UpdateRectangles();

            // Update the bounding box for the items
            buttonRect = new System.Drawing.Rectangle(boundingBox.Right - boundingBox.Height, boundingBox.Top,
                boundingBox.Height, boundingBox.Height);

            textRect = boundingBox;
            textRect.Size = new System.Drawing.Size(textRect.Width - buttonRect.Width, textRect.Height);

            dropDownRect = textRect;
            dropDownRect.Offset(0, (int)(0.9f * textRect.Height));
            dropDownRect.Size = new System.Drawing.Size(dropDownRect.Width - scrollWidth, dropDownRect.Height + dropHeight);

            // 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
            scrollbarControl.SetLocation(dropDownRect.Right, dropDownRect.Top + 2);
            scrollbarControl.SetSize(scrollWidth, dropDownRect.Height - 2);
            FontNode fNode = DialogResourceManager.GetGlobalInstance().GetFontNode((int)(elementList[2] as Element).FontIndex);
            if ((fNode != null) && (fNode.Height > 0))
            {
                scrollbarControl.PageSize = (int)(dropDownTextRect.Height / fNode.Height);

                // The selected item may have been scrolled off the page.
                // Ensure that it is in page again.
                scrollbarControl.ShowItem(selectedIndex);
            }
        }

        /// <summary>Sets the drop height of this control</summary>
        public void SetDropHeight(int height) { dropHeight = height; UpdateRectangles(); }
        /// <summary>Sets the scroll bar width of this control</summary>
        public void SetScrollbarWidth(int width) { scrollWidth = width; UpdateRectangles(); }
        /// <summary>Can this control have focus</summary>
        public override bool CanHaveFocus { get { return (IsVisible && IsEnabled); } }
        /// <summary>Number of items current in the list</summary>
        public int NumberItems { get { return itemList.Count; } }
        /// <summary>Indexer for items in the list</summary>
        public ComboBoxItem this[int index]
        {
            get { return (ComboBoxItem)itemList[index]; }
        }

        /// <summary>Initialize the scrollbar control here</summary>
        public override void OnInitialize()
        {
            parentDialog.InitializeControl(scrollbarControl);
        }

        /// <summary>Called when focus leaves the control</summary>
        public override void OnFocusOut()
        {
            // Call base first
            base.OnFocusOut ();
            isComboOpen = false;
        }
        /// <summary>Called when the control's hotkey is pressed</summary>
        public override void OnHotKey()
        {
            if (isComboOpen)
                return; // Nothing to do yet

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

            selectedIndex++;
            if (selectedIndex >= itemList.Count)
                selectedIndex = 0;

            focusedIndex = selectedIndex;
            RaiseChangedEvent(this, true);
        }


        /// <summary>Called when the control needs to handle the keyboard</summary>
        public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            const uint RepeatMask = (0x40000000);

            if (!IsEnabled || !IsVisible)
                return false;

            // Let the scroll bar have a chance to handle it first
            if (scrollbarControl.HandleKeyboard(msg, wParam, lParam))
                return true;

            switch (msg)
            {
                case NativeMethods.WindowMessage.KeyDown:
                {
                    switch((System.Windows.Forms.Keys)wParam.ToInt32())
                    {
                        case System.Windows.Forms.Keys.Return:
                        {
                            if (isComboOpen)
                            {
                                if (selectedIndex != focusedIndex)
                                {
                                    selectedIndex = focusedIndex;
                                    RaiseChangedEvent(this, true);
                                }
                                isComboOpen = false;

                                if (!Parent.IsUsingKeyboardInput)
                                    Dialog.ClearFocus();

                                return true;
                            }
                            break;
                        }
                        case System.Windows.Forms.Keys.F4:
                        {
                            // Filter out auto repeats
                            if ((lParam.ToInt32() & RepeatMask) != 0)
                                return true;

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

                                if (!Parent.IsUsingKeyboardInput)
                                    Dialog.ClearFocus();
                            }

                            return true;
                        }
                        case System.Windows.Forms.Keys.Left:
                        case System.Windows.Forms.Keys.Up:
                        {
                            if (focusedIndex > 0)
                            {
                                focusedIndex--;
                                selectedIndex = focusedIndex;
                                if (!isComboOpen)
                                    RaiseChangedEvent(this, true);
                            }
                            return true;
                        }
                        case System.Windows.Forms.Keys.Right:
                        case System.Windows.Forms.Keys.Down:
                        {
                            if (focusedIndex + 1 < (int)NumberItems)
                            {
                                focusedIndex++;
                                selectedIndex = focusedIndex;
                                if (!isComboOpen)
                                    RaiseChangedEvent(this, true);
                            }
                            return true;
                        }
                    }
                    break;
                }
            }

            return false;
        }

        /// <summary>Called when the control should handle the mouse</summary>
        public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false; // Nothing to do

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

            // Ok, scrollbar didn't handle it, move on
            switch(msg)
            {
                case NativeMethods.WindowMessage.MouseMove:
                {
                    if (isComboOpen && dropDownRect.Contains(pt))
                    {
                        // Determine which item has been selected
                        for (int i = 0; i < itemList.Count; i++)
                        {
                            ComboBoxItem cbi = (ComboBoxItem)itemList[i];
                            if (cbi.IsItemVisible && cbi.ItemRect.Contains(pt))
                            {
                                focusedIndex = i;
                            }
                        }
                        return true;
                    }
                    break;
                }
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                case NativeMethods.WindowMessage.LeftButtonDown:
                {
                    if (ContainsPoint(pt))
                    {
                        // Pressed while inside the control
                        isPressed = true;
                        Parent.SampleFramework.Window.Capture = true;

                        if (!hasFocus)
                            Dialog.RequestFocus(this);

                        // Toggle dropdown
                        if (hasFocus)
                        {
                            isComboOpen = !isComboOpen;
                            if (!isComboOpen)
                            {
                                if (!parentDialog.IsUsingKeyboardInput)
                                    Dialog.ClearFocus();
                            }
                        }

                        return true;
                    }

                    // Perhaps this click is within the dropdown
                    if (isComboOpen && dropDownRect.Contains(pt))
                    {
                        // Determine which item has been selected
                        for (int i = scrollbarControl.TrackPosition; i < itemList.Count; i++)
                        {
                            ComboBoxItem cbi = (ComboBoxItem)itemList[i];
                            if (cbi.IsItemVisible && cbi.ItemRect.Contains(pt))
                            {
                                selectedIndex = focusedIndex = i;
                                RaiseChangedEvent(this, true);

                                isComboOpen = false;

                                if (!parentDialog.IsUsingKeyboardInput)
                                    Dialog.ClearFocus();

                                break;
                            }
                        }
                        return true;
                    }
                    // Mouse click not on main control or in dropdown, fire an event if needed
                    if (isComboOpen)
                    {
                        focusedIndex = selectedIndex;
                        RaiseChangedEvent(this, true);
                        isComboOpen = false;
                    }

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

                    // Release focus if appropriate
                    if (!parentDialog.IsUsingKeyboardInput)
                        Dialog.ClearFocus();

                    break;
                }
                case NativeMethods.WindowMessage.LeftButtonUp:
                {
                    if (isPressed && ContainsPoint(pt))
                    {
                        // Button click
                        isPressed = false;
                        Parent.SampleFramework.Window.Capture = false;
                        return true;
                    }
                    break;
                }
                case NativeMethods.WindowMessage.MouseWheel:
                {
                    int zdelta = (short)NativeMethods.HiWord((uint)wParam.ToInt32()) / Dialog.WheelDelta;
                    if (isComboOpen)
                    {
                        scrollbarControl.Scroll(-zdelta * System.Windows.Forms.SystemInformation.MouseWheelScrollLines);
                    }
                    else
                    {
                        if (zdelta > 0)
                        {
                            if (focusedIndex > 0)
                            {
                                focusedIndex--;
                                selectedIndex = focusedIndex;
                                if (!isComboOpen)
                                {
                                    RaiseChangedEvent(this, true);
                                }
                            }
                        }
                        else
                        {
                            if (focusedIndex +1 < NumberItems)
                            {
                                focusedIndex++;
                                selectedIndex = focusedIndex;
                                if (!isComboOpen)
                                {
                                    RaiseChangedEvent(this, true);
                                }
                            }
                        }
                    }
                    return true;
                }
            }

            // Didn't handle it
            return false;
        }

        /// <summary>Called when the control should be rendered</summary>
        public override void Render(Device device, float elapsedTime)
        {
            ControlState state = ControlState.Normal;
            if (!isComboOpen)
                state = ControlState.Hidden;

            // Dropdown box
            Element e = elementList[ComboBox.DropdownLayer] as Element;
            
            // If we have not initialized the scroll bar page size,
            // do that now.
            if (!isScrollBarInit)
            {
                FontNode fNode = DialogResourceManager.GetGlobalInstance().GetFontNode((int)e.FontIndex);
                if ((fNode != null) && (fNode.Height > 0))
                    scrollbarControl.PageSize = (int)(dropDownTextRect.Height / fNode.Height);
                else
                    scrollbarControl.PageSize = dropDownTextRect.Height;

                isScrollBarInit = true;
            }

            if (isComboOpen)
                scrollbarControl.Render(device, elapsedTime);

            // Blend current color
            e.TextureColor.Blend(state, elapsedTime);
            e.FontColor.Blend(state, elapsedTime);
            parentDialog.DrawSprite(e, dropDownRect);

            // Selection outline
            Element selectionElement = elementList[ComboBox.SelectionLayer] as Element;
            selectionElement.TextureColor.Current = e.TextureColor.Current;
            selectionElement.FontColor.Current = selectionElement.FontColor.States[(int)ControlState.Normal];

            FontNode font = DialogResourceManager.GetGlobalInstance().GetFontNode((int)e.FontIndex);
            int currentY = dropDownTextRect.Top;
            int remainingHeight = dropDownTextRect.Height;

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

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

                cbi.ItemRect = new System.Drawing.Rectangle(dropDownTextRect.Left, currentY,
                    dropDownTextRect.Width, (int)font.Height);
                cbi.IsItemVisible = true;
                currentY += (int)font.Height;
                itemList[i] = cbi; // Store this back in list

                if (isComboOpen)
                {
                    if (focusedIndex == i)
                    {
                        System.Drawing.Rectangle rect = new System.Drawing.Rectangle(
                            dropDownRect.Left, cbi.ItemRect.Top - 2, dropDownRect.Width,
                            cbi.ItemRect.Height + 4);
                        parentDialog.DrawSprite(selectionElement, rect);
                        parentDialog.DrawText(cbi.ItemText, selectionElement, cbi.ItemRect);
                    }
                    else
                    {
                        parentDialog.DrawText(cbi.ItemText, e, cbi.ItemRect);
                    }
                }
            }

            int offsetX = 0;
            int offsetY = 0;

            state = ControlState.Normal;
            if (IsVisible == false)
                state = ControlState.Hidden;
            else if (IsEnabled == false)
                state = ControlState.Disabled;
            else if (isPressed)
            {
                state = ControlState.Pressed;
                offsetX = 1;
                offsetY = 2;
            }
            else if (isMouseOver)
            {
                state = ControlState.MouseOver;
                offsetX = -1;
                offsetY = -2;
            }
            else if (hasFocus)
                state = ControlState.Focus;

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

            // Button
            e = elementList[ComboBox.ComboButtonLayer] as Element;
            
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            
            System.Drawing.Rectangle windowRect = buttonRect;
            windowRect.Offset(offsetX, offsetY);
            // Draw sprite
            parentDialog.DrawSprite(e, windowRect);

            if (isComboOpen)
                state = ControlState.Pressed;

            // Main text box
            e = elementList[ComboBox.MainLayer] as Element;
            
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            e.FontColor.Blend(state, elapsedTime, blendRate);

            // Draw sprite
            parentDialog.DrawSprite(e, textRect);

            if (selectedIndex >= 0 && selectedIndex < itemList.Count)
            {
                try
                {
                    ComboBoxItem cbi = (ComboBoxItem)itemList[selectedIndex];
                    parentDialog.DrawText(cbi.ItemText, e, textRect);
                }
                catch {} // Ignore
            }

        }

        #region Item Controlling methods
        /// <summary>Adds an item to the combo box control</summary>
        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;
            itemList.Add(newitem);

            // Update the scrollbar with the new range
            scrollbarControl.SetTrackRange(0, itemList.Count);

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

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

            // Update the scrollbar with the new range
            scrollbarControl.SetTrackRange(0, itemList.Count);

            if (selectedIndex >= itemList.Count)
                selectedIndex = itemList.Count - 1;
        }

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

            // Update scroll bar and index
            scrollbarControl.SetTrackRange(0, 1);
            focusedIndex = selectedIndex = -1;
        }

        /// <summary>Determines whether this control contains an item</summary>
        public bool ContainsItem(string text, int start)
        {
            return (FindItem(text, start) != -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 (selectedIndex < 0)
                return null; // Nothing selected

            ComboBoxItem cbi = (ComboBoxItem)itemList[selectedIndex];
            return cbi.ItemData;
        }

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

            return (ComboBoxItem)itemList[selectedIndex];
        }

        /// <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)itemList[index];
            return cbi.ItemData;
        }

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

            for(int i = start; i < itemList.Count; i++)
            {
                ComboBoxItem cbi = (ComboBoxItem)itemList[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.");

            focusedIndex = selectedIndex = 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.");

            focusedIndex = selectedIndex = index;
            RaiseChangedEvent(this, false);
        }

        /// <summary>Sets the selected item by data</summary>
        public void SetSelectedByData(object data)
        {
            for (int index = 0; index < itemList.Count; index++)
            {
                ComboBoxItem cbi = (ComboBoxItem)itemList[index];
                if (cbi.ItemData.ToString().Equals(data.ToString()))
                {
                    focusedIndex = selectedIndex = 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
    }
    #endregion

    #region Slider Control
    /// <summary>Slider control</summary>
    public class Slider : Control
    {
        public const int TrackLayer = 0;
        public const int ButtonLayer = 1;
        #region Instance Data
        public event EventHandler ValueChanged;
        protected int currentValue; 
        protected int maxValue;
        protected int minValue;
        
        protected int dragX; // Mouse position at the start of the drag
        protected int dragOffset; // Drag offset from the center of the button
        protected int buttonX;

        protected bool isPressed;
        protected System.Drawing.Rectangle buttonRect;

        /// <summary>Slider's can always have focus</summary>
        public override bool CanHaveFocus { get { return true; }}

        /// <summary>Current value of the slider</summary>
        protected void RaiseValueChanged(Slider sender, bool wasTriggeredByUser)
        {
            // Discard events triggered programatically if these types of events haven't been
            // enabled
            if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
                return;

            if (ValueChanged != null)
                ValueChanged(sender, EventArgs.Empty);
        }
        /// <summary>Current value of the slider</summary>
        public int Value { get { return currentValue; } set { SetValueInternal(value, false); } }
        /// <summary>Sets the range of the slider</summary>
        public void SetRange(int min, int max)
        {
            minValue = min;
            maxValue = max;
            SetValueInternal(currentValue, false);
        }

        /// <summary>Sets the value internally and fires the event if needed</summary>
        protected void SetValueInternal(int newValue, bool fromInput)
        {
            // Clamp to the range
            newValue = Math.Max(minValue, newValue);
            newValue = Math.Min(maxValue, newValue);
            if (newValue == currentValue)
                return;

            // Update the value, the rects, then fire the events if necessar
            currentValue = newValue; 
            UpdateRectangles();
            RaiseValueChanged(this, fromInput);
        }
        #endregion

        /// <summary>Create new button instance</summary>
        public Slider(Dialog parent): base(parent)
        {
            controlType = ControlType.Slider;
            parentDialog = parent;

            isPressed = false;
            minValue = 0;
            maxValue = 100;
            currentValue = 50;
        }

        /// <summary>Does the control contain this point?</summary>
        public override bool ContainsPoint(System.Drawing.Point pt)
        {
            return boundingBox.Contains(pt) || buttonRect.Contains(pt);
        }

        /// <summary>Update the rectangles for the control</summary>
        protected override void UpdateRectangles()
        {
            // First get the bounding box
            base.UpdateRectangles ();

            // Create the button rect
            buttonRect = boundingBox;
            buttonRect.Width = buttonRect.Height; // Make it square

            // Offset it 
            buttonRect.Offset(-buttonRect.Width / 2, 0);
            buttonX = (int)((currentValue - minValue) * (float)boundingBox.Width / (maxValue - minValue) );
            buttonRect.Offset(buttonX, 0);
        }

        /// <summary>Gets a value from a position</summary>
        public int ValueFromPosition(int x)
        {
            float valuePerPixel = ((float)(maxValue - minValue) / (float)boundingBox.Width);
            return (int)(0.5f + minValue + valuePerPixel * (x - boundingBox.Left));
        }

        /// <summary>Handle mouse input input</summary>
        public override bool HandleMouse(Microsoft.Samples.DirectX.UtilityToolkit.NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            switch(msg)
            {
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                case NativeMethods.WindowMessage.LeftButtonDown:
                {
                    if (buttonRect.Contains(pt))
                    {
                        // Pressed while inside the control
                        isPressed = true;
                        Parent.SampleFramework.Window.Capture = true;

                        dragX = pt.X;
                        dragOffset = buttonX - dragX;
                        if (!hasFocus)
                            Dialog.RequestFocus(this);
                        
                        return true;
                    }
                    if (boundingBox.Contains(pt))
                    {
                        if (pt.X > buttonX + controlX)
                        {
                            SetValueInternal(currentValue + 1, true);
                            return true;
                        }
                        if (pt.X < buttonX + controlX)
                        {
                            SetValueInternal(currentValue - 1, true);
                            return true;
                        }
                    }

                    break;
                }
                case NativeMethods.WindowMessage.LeftButtonUp:
                {
                    if (isPressed)
                    {
                        isPressed = false;
                        Parent.SampleFramework.Window.Capture = false;
                        Dialog.ClearFocus();
                        RaiseValueChanged(this, true);
                        return true;
                    }
                    break;
                }
                case NativeMethods.WindowMessage.MouseMove:
                {
                    if (isPressed)
                    {
                        SetValueInternal(ValueFromPosition(controlX + pt.X + dragOffset), true);
                        return true;
                    }
                    break;
                }
            }
            return false;
        }

        /// <summary>Handle keyboard input</summary>
        public override bool HandleKeyboard(Microsoft.Samples.DirectX.UtilityToolkit.NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            if (msg == NativeMethods.WindowMessage.KeyDown)
            {
                switch((System.Windows.Forms.Keys)wParam.ToInt32())
                {
                    case System.Windows.Forms.Keys.Home:
                        SetValueInternal(minValue, true);
                        return true;
                    case System.Windows.Forms.Keys.End:
                        SetValueInternal(maxValue, true);
                        return true;
                    case System.Windows.Forms.Keys.Prior:
                    case System.Windows.Forms.Keys.Left:
                    case System.Windows.Forms.Keys.Up:
                        SetValueInternal(currentValue - 1, true);
                        return true;
                    case System.Windows.Forms.Keys.Next:
                    case System.Windows.Forms.Keys.Right:
                    case System.Windows.Forms.Keys.Down:
                        SetValueInternal(currentValue + 1, true);
                        return true;
                }
            }

            return false;
        }

    
        /// <summary>Render the slider</summary>
        public override void Render(Device device, float elapsedTime)
        {
            ControlState state = ControlState.Normal;
            if (IsVisible == false)
            {
                state = ControlState.Hidden;
            }
            else if (IsEnabled == false)
            {
                state = ControlState.Disabled;
            }
            else if (isPressed)
            {
                state = ControlState.Pressed;
            }
            else if (isMouseOver)
            {
                state = ControlState.MouseOver;
            }
            else if (hasFocus)
            {
                state = ControlState.Focus;
            }

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

            Element e = elementList[Slider.TrackLayer] as Element;
            
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            parentDialog.DrawSprite(e, boundingBox);

            e = elementList[Slider.ButtonLayer] as Element;
            // Blend current color
            e.TextureColor.Blend(state, elapsedTime, blendRate);
            parentDialog.DrawSprite(e, buttonRect);
        }
    }
    #endregion

    #region Listbox Control

    /// <summary>Style of the list box</summary>
    public enum ListBoxStyle
    {
        SingleSelection,
        Multiselection,
    }

    /// <summary>Stores data for a list box item</summary>
    public struct ListBoxItem
    {
        public string ItemText;
        public object ItemData;
        public System.Drawing.Rectangle ItemRect;
        public bool IsItemSelected;
    }
    /// <summary>List box control</summary>
    public class ListBox : Control
    {
        public const int MainLayer = 0;
        public const int SelectionLayer = 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(ListBox sender, bool wasTriggeredByUser)
        {
            // Discard events triggered programatically if these types of events haven't been
            // enabled
            if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
                return;

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

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

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

        #region Instance data
        private bool isScrollBarInit;
        protected System.Drawing.Rectangle textRect; // Text rendering bound
        protected System.Drawing.Rectangle selectionRect; // Selection box bound
        protected ScrollBar scrollbarControl; 
        protected int scrollWidth;
        protected int border;
        protected int margin;
        protected int textHeight; // Height of a single line of text
        protected int selectedIndex;
        protected int selectedStarted;
        protected bool isDragging;
        protected ListBoxStyle style;
 
        protected ArrayList itemList;
        #endregion

        /// <summary>Create a new list box control</summary>
        public ListBox(Dialog parent) : base(parent)
        {
            // Store control type and parent dialog
            controlType = ControlType.ListBox;
            parentDialog = parent;
            // Create the scrollbar control too
            scrollbarControl = new ScrollBar(parent);

            // Set some default items
            style = ListBoxStyle.SingleSelection;
            scrollWidth = 16;
            selectedIndex = -1;
            selectedStarted = 0;
            isDragging = false;
            margin = 5;
            border = 6;
            textHeight = 0;
            isScrollBarInit = false;

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

        /// <summary>Update the rectangles for the list box control</summary>
        protected override void UpdateRectangles()
        {
            // Get bounding box
            base.UpdateRectangles();

            // Calculate the size of the selection rectangle
            selectionRect = boundingBox;
            selectionRect.Width -= scrollWidth;
            selectionRect.Inflate(-border, -border);
            textRect = selectionRect;
            textRect.Inflate(-margin, 0);

            // Update the scroll bars rects too
            scrollbarControl.SetLocation(boundingBox.Right - scrollWidth, boundingBox.Top);
            scrollbarControl.SetSize(scrollWidth, height);
            FontNode fNode = DialogResourceManager.GetGlobalInstance().GetFontNode((int)(elementList[0] as Element).FontIndex);
            if ((fNode != null) && (fNode.Height > 0))
            {
                scrollbarControl.PageSize = (int)(textRect.Height / fNode.Height);

                // The selected item may have been scrolled off the page.
                // Ensure that it is in page again.
                scrollbarControl.ShowItem(selectedIndex);
            }
        }
        /// <summary>Sets the scroll bar width of this control</summary>
        public void SetScrollbarWidth(int width) { scrollWidth = width; UpdateRectangles(); }
        /// <summary>Can this control have focus</summary>
        public override bool CanHaveFocus { get { return (IsVisible && IsEnabled); } }
        /// <summary>Sets the style of the listbox</summary>
        public ListBoxStyle Style { get { return style; } set { style = value; } } 
        /// <summary>Number of items current in the list</summary>
        public int NumberItems { get { return itemList.Count; } }
        /// <summary>Indexer for items in the list</summary>
        public ListBoxItem this[int index]
        {
            get { return (ListBoxItem)itemList[index]; }
        }

        /// <summary>Initialize the scrollbar control here</summary>
        public override void OnInitialize()
        {
            parentDialog.InitializeControl(scrollbarControl);
        }


        /// <summary>Called when the control needs to handle the keyboard</summary>
        public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            // Let the scroll bar have a chance to handle it first
            if (scrollbarControl.HandleKeyboard(msg, wParam, lParam))
                return true;

            switch (msg)
            {
                case NativeMethods.WindowMessage.KeyDown:
                {
                    switch((System.Windows.Forms.Keys)wParam.ToInt32())
                    {
                        case System.Windows.Forms.Keys.Up:
                        case System.Windows.Forms.Keys.Down:
                        case System.Windows.Forms.Keys.Next:
                        case System.Windows.Forms.Keys.Prior:
                        case System.Windows.Forms.Keys.Home:
                        case System.Windows.Forms.Keys.End:
                        {
                            // If no items exists, do nothing
                            if (itemList.Count == 0)
                                return true;

                            int oldSelected = selectedIndex;

                            // Adjust selectedIndex
                            switch((System.Windows.Forms.Keys)wParam.ToInt32())
                            {
                                case System.Windows.Forms.Keys.Up: --selectedIndex; break;
                                case System.Windows.Forms.Keys.Down: ++selectedIndex; break;
                                case System.Windows.Forms.Keys.Next: selectedIndex += scrollbarControl.PageSize - 1; break;
                                case System.Windows.Forms.Keys.Prior: selectedIndex -= scrollbarControl.PageSize - 1; break;
                                case System.Windows.Forms.Keys.Home: selectedIndex = 0; break;
                                case System.Windows.Forms.Keys.End: selectedIndex = itemList.Count - 1; break;
                            }

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

                            // Did the selection change?
                            if (oldSelected != selectedIndex)
                            {
                                if (style == ListBoxStyle.Multiselection)
                                {
                                    // Clear all selection
                                    for(int i = 0; i < itemList.Count; i++)
                                    {
                                        ListBoxItem lbi = (ListBoxItem)itemList[i];
                                        lbi.IsItemSelected = false;
                                        itemList[i] = lbi;
                                    }

                                    // Is shift being held down?
                                    bool shiftDown = ((NativeMethods.GetAsyncKeyState
                                        ((int)System.Windows.Forms.Keys.ShiftKey) & 0x8000) != 0);

                                    if (shiftDown)
                                    {
                                        // Select all items from the start selection to current selected index
                                        int end = Math.Max(selectedStarted, selectedIndex);
                                        for(int i = Math.Min(selectedStarted, selectedIndex); i <= end; ++i)
                                        {
                                            ListBoxItem lbi = (ListBoxItem)itemList[i];
                                            lbi.IsItemSelected = true;
                                            itemList[i] = lbi;
                                        }
                                    }
                                    else
                                    {
                                        ListBoxItem lbi = (ListBoxItem)itemList[selectedIndex];
                                        lbi.IsItemSelected = true;
                                        itemList[selectedIndex] = lbi;

                                        // Update selection start
                                        selectedStarted = selectedIndex;
                                    }

                                }
                                else // Update selection start
                                    selectedStarted = selectedIndex;

                                // adjust scrollbar
                                scrollbarControl.ShowItem(selectedIndex);
                                RaiseSelectionEvent(this, true);
                            }
                        }
                        return true;
                    }
                    break;
                }
            }

            return false;
        }

        /// <summary>Called when the control should handle the mouse</summary>
        public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
        {
            const int ShiftModifier = 0x0004;
            const int ControlModifier = 0x0008;

            if (!IsEnabled || !IsVisible)
                return false; // Nothing to do

            // First acquire focus
            if (msg == NativeMethods.WindowMessage.LeftButtonDown)
                if (!hasFocus)
                    Dialog.RequestFocus(this);


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

            // Ok, scrollbar didn't handle it, move on
            switch(msg)
            {
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                case NativeMethods.WindowMessage.LeftButtonDown:
                {
                    // Check for clicks in the text area
                    if (itemList.Count > 0 && selectionRect.Contains(pt))
                    {
                        // Compute the index of the clicked item
                        int clicked = 0;
                        if (textHeight > 0)
                            clicked = scrollbarControl.TrackPosition + (pt.Y - textRect.Top) / textHeight;
                        else
                            clicked = -1;

                        // Only proceed if the click falls ontop of an item
                        if (clicked >= scrollbarControl.TrackPosition &&
                            clicked < itemList.Count &&
                            clicked < scrollbarControl.TrackPosition + scrollbarControl.PageSize )
                        {
                            Parent.SampleFramework.Window.Capture = true;
                            isDragging = true;

                            // 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 true;
                            }

                            selectedIndex = clicked;
                            if ( (wParam.ToInt32() & ShiftModifier) == 0)
                                selectedStarted = selectedIndex; // Shift isn't down

                            // If this is a multi-selection listbox, update per-item
                            // selection data.
                            if (style == ListBoxStyle.Multiselection)
                            {
                                // Determine behavior based on the state of Shift and Ctrl
                                ListBoxItem selectedItem = (ListBoxItem)itemList[selectedIndex];
                                if ((wParam.ToInt32() & (ShiftModifier | ControlModifier)) == ControlModifier)
                                {
                                    // Control click, reverse the selection
                                    selectedItem.IsItemSelected = !selectedItem.IsItemSelected;
                                    itemList[selectedIndex] = 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(selectedStarted, selectedIndex);
                                    int end = Math.Max(selectedStarted, selectedIndex);

                                    // Unselect everthing before the beginning
                                    for(int i = 0; i < begin; ++i)
                                    {
                                        ListBoxItem lb = (ListBoxItem)itemList[i];
                                        lb.IsItemSelected = false;
                                        itemList[i] = lb;
                                    }
                                    // unselect everything after the end
                                    for(int i = end + 1; i < itemList.Count; ++i)
                                    {
                                        ListBoxItem lb = (ListBoxItem)itemList[i];
                                        lb.IsItemSelected = false;
                                        itemList[i] = lb;
                                    }

                                    // Select everything between
                                    for(int i = begin; i <= end; ++i)
                                    {
                                        ListBoxItem lb = (ListBoxItem)itemList[i];
                                        lb.IsItemSelected = true;
                                        itemList[i] = lb;
                                    }
                                }
                                else if ((wParam.ToInt32() & (ShiftModifier | ControlModifier)) == (ShiftModifier | ControlModifier))
                                {
                                    // Control-Shift-click.

                                    // The behavior is:
                                    //   Set all items from selectedStarted to selectedIndex to
                                    //     the same state as selectedStarted, not including selectedIndex.
                                    //   Set selectedIndex to selected.
                                    int begin = Math.Min(selectedStarted, selectedIndex);
                                    int end = Math.Max(selectedStarted, selectedIndex);

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

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

                                    selectedItem.IsItemSelected = true;
                                    itemList[selectedIndex] = selectedItem;

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

                                    selectedIndex = selectedStarted;
                                }
                                else
                                {
                                    // Simple click.  Clear all items and select the clicked
                                    // item.
                                    for(int i = 0; i < itemList.Count; ++i)
                                    {
                                        ListBoxItem lb = (ListBoxItem)itemList[i];
                                        lb.IsItemSelected = false;
                                        itemList[i] = lb;
                                    }
                                    selectedItem.IsItemSelected = true;
                                    itemList[selectedIndex] = selectedItem;
                                }
                            } // End of multi-selection case
                            RaiseSelectionEvent(this, true);
                        }
                        return true;
                    }
                    break;
                }
                case NativeMethods.WindowMessage.LeftButtonUp:
                {
                    Parent.SampleFramework.Window.Capture = false;
                    isDragging = false;

                    if (selectedIndex != -1)
                    {
                        // Set all items between selectedStarted and selectedIndex to
                        // the same state as selectedStarted
                        int end = Math.Max(selectedStarted, selectedIndex);
                        for (int i = Math.Min(selectedStarted, selectedIndex) + 1; i < end; ++i)
                        {
                            ListBoxItem lb = (ListBoxItem)itemList[i];
                            lb.IsItemSelected = ((ListBoxItem)itemList[selectedStarted]).IsItemSelected;
                            itemList[i] = lb;
                        }
                        ListBoxItem lbs = (ListBoxItem)itemList[selectedIndex];
                        lbs.IsItemSelected = ((ListBoxItem)itemList[selectedStarted]).IsItemSelected;
                        itemList[selectedIndex] = lbs;

                        // If selectedStarted and selectedIndex are not the same,
                        // the user has dragged the mouse to make a selection.
                        // Notify the application of this.
                        if (selectedIndex != selectedStarted)
                            RaiseSelectionEvent(this, true);
                    }
                    break;
                }
                case NativeMethods.WindowMessage.MouseWheel:
                {
                    int lines = System.Windows.Forms.SystemInformation.MouseWheelScrollLines;
                    int scrollAmount = (int)(NativeMethods.HiWord((uint)wParam.ToInt32()) / Dialog.WheelDelta * lines);
                    scrollbarControl.Scroll(-scrollAmount);
                    break;
                }

                case NativeMethods.WindowMessage.MouseMove:
                {
                    if (isDragging)
                    {
                        // compute the index of the item below the cursor
                        int itemIndex = -1;
                        if (textHeight > 0)
                            itemIndex = scrollbarControl.TrackPosition + (pt.Y - textRect.Top) / textHeight;

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

            // Didn't handle it
            return false;
        }

        /// <summary>Called when the control should be rendered</summary>
        public override void Render(Device device, float elapsedTime)
        {
            if (!IsVisible)
                return; // Nothing to render
            
            Element e = elementList[ListBox.MainLayer] as Element;

            // Blend current color
            e.TextureColor.Blend(ControlState.Normal, elapsedTime);
            e.FontColor.Blend(ControlState.Normal, elapsedTime);
            
            Element selectedElement = elementList[ListBox.SelectionLayer] as Element;

            // Blend current color
            selectedElement.TextureColor.Blend(ControlState.Normal, elapsedTime);
            selectedElement.FontColor.Blend(ControlState.Normal, elapsedTime);

            parentDialog.DrawSprite(e, boundingBox);

            // Render the text
            if (itemList.Count > 0)
            {
                // Find out the height of a single line of text
                System.Drawing.Rectangle rc = textRect;
                System.Drawing.Rectangle sel = selectionRect;
                rc.Height = (int)(DialogResourceManager.GetGlobalInstance().GetFontNode((int)e.FontIndex).Height);
                textHeight = rc.Height;

                // If we have not initialized the scroll bar page size,
                // do that now.
                if (!isScrollBarInit)
                {
                    if (textHeight > 0)
                        scrollbarControl.PageSize = (int)(textRect.Height / textHeight);
                    else
                        scrollbarControl.PageSize = textRect.Height;

                    isScrollBarInit = true;
                }
                rc.Width = textRect.Width;
                for (int i = scrollbarControl.TrackPosition; i < itemList.Count; ++i)
                {
                    if (rc.Bottom > textRect.Bottom)
                        break;

                    ListBoxItem lb = (ListBoxItem)itemList[i];

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

                    if ( (selectedIndex == i) && (style == ListBoxStyle.SingleSelection) )
                        isSelectedStyle = true;
                    else if (style == ListBoxStyle.Multiselection)
                    {
                        if (isDragging && ( ( i >= selectedIndex && i < selectedStarted) || 
                            (i <= selectedIndex && i > selectedStarted) ) )
                        {
                            ListBoxItem selStart = (ListBoxItem)itemList[selectedStarted];
                            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;
                        parentDialog.DrawSprite(selectedElement, sel);
                        parentDialog.DrawText(lb.ItemText, selectedElement, rc);
                    }
                    else
                        parentDialog.DrawText(lb.ItemText, e, rc);

                    rc.Offset(0, textHeight);
                }
            }

            // Render the scrollbar finally
            scrollbarControl.Render(device, elapsedTime);
        }

        
        #region Item Controlling methods
        /// <summary>Adds an item to the list box control</summary>
        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
            ListBoxItem newitem = new ListBoxItem();
            newitem.ItemText = text;
            newitem.ItemData = data;
            newitem.IsItemSelected = false;
            itemList.Add(newitem);

            // Update the scrollbar with the new range
            scrollbarControl.SetTrackRange(0, itemList.Count);
        }
        /// <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;
            itemList.Insert(index, newitem);

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

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

            // Update the scrollbar with the new range
            scrollbarControl.SetTrackRange(0, itemList.Count);

            if (selectedIndex >= itemList.Count)
                selectedIndex = itemList.Count - 1;

            RaiseSelectionEvent(this, true);
        }

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

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

        /// <summary>
        /// For single-selection listbox, returns the index of the selected item.
        /// For multi-selection, returns the first selected item after the previousSelected position.
        /// 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(int previousSelected)
        {
            if (previousSelected < -1)
                return -1;

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

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

        /// <summary>Sets the border and margin sizes</summary>
        public void SetBorder(int borderSize, int marginSize)
        {
            border = borderSize;
            margin = marginSize;
            UpdateRectangles();
        }

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

            int oldSelected = selectedIndex;

            // Select the new item
            selectedIndex = newIndex;

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

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

                // Update selection start
                selectedStarted = selectedIndex;

                // adjust scrollbar
                scrollbarControl.ShowItem(selectedIndex);
            }
            RaiseSelectionEvent(this, true);
        }
        #endregion
    }
    #endregion

    /// <summary>A basic edit box</summary>
    public class EditBox : Control
    {
        #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;
        /// <summary>Raises the changed event</summary>
        protected void RaiseChangedEvent(EditBox sender, bool wasTriggeredByUser)
        {
            // Discard events triggered programatically if these types of events haven't been
            // enabled
            if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
                return;

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

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

        #region Class Data
        protected System.Windows.Forms.RichTextBox textData; // Text data
        protected int border; // Border of the window
        protected int spacing; // Spacing between the text and the edge of border
        protected System.Drawing.Rectangle textRect; // Bounding rectangle for the text
        protected System.Drawing.Rectangle[] elementRects = new System.Drawing.Rectangle[9];
        protected double blinkTime; // Caret blink time in milliseconds
        protected double lastBlink; // Last timestamp of caret blink
        protected bool isCaretOn; // Flag to indicate whether caret is currently visible
        protected int caretPosition; // Caret position, in characters
        protected bool isInsertMode; // If true, control is in insert mode. Else, overwrite mode.
        protected int firstVisible;  // First visible character in the edit control
        protected ColorValue textColor; // Text color
        protected ColorValue selectedTextColor; // Selected Text color
        protected ColorValue selectedBackColor; // Selected background color
        protected ColorValue caretColor; // Caret color

        // Mouse-specific
        protected bool isMouseDragging; // True to indicate the drag is in progress

        protected static bool isHidingCaret; // If true, we don't render the caret.
        
        #endregion

        #region Simple overrides/properties/methods
        /// <summary>Can the edit box have focus</summary>
        public override bool CanHaveFocus { get { return (IsVisible && IsEnabled); } }
        /// <summary>Update the spacing</summary>
        public void SetSpacing(int space) { spacing = space; UpdateRectangles(); }
        /// <summary>Update the border</summary>
        public void SetBorderWidth(int b) { border = b; UpdateRectangles(); }
        /// <summary>Update the text color</summary>
        public void SetTextColor(ColorValue color) { textColor = color; }
        /// <summary>Update the text selected color</summary>
        public void SetSelectedTextColor(ColorValue color) { selectedTextColor = color; }
        /// <summary>Update the selected background color</summary>
        public void SetSelectedBackColor(ColorValue color) { selectedBackColor = color; }
        /// <summary>Update the caret color</summary>
        public void SetCaretColor(ColorValue color) { caretColor = color; }

        /// <summary>Get or sets the text</summary>
        public string Text { get { return textData.Text; } set { SetText(value, false); } }
        /// <summary>Gets a copy of the text</summary>
        public string GetTextCopy() { return string.Copy(textData.Text); }
        #endregion

        /// <summary>Creates a new edit box control</summary>
        public EditBox(Dialog parent) : base(parent)
        {
            controlType = ControlType.EditBox;
            parentDialog = parent;

            border = 5; // Default border
            spacing = 4; // default spacing
            isCaretOn = true;

            textData = new System.Windows.Forms.RichTextBox();
            // Create the control
            textData.Visible = true;
            textData.Font = new System.Drawing.Font("Arial", 8.0f);
            textData.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
            textData.Multiline = false;
            textData.Text = string.Empty;
            textData.MaxLength = ushort.MaxValue; // 65k characters should be plenty
            textData.WordWrap = false;
            // Now create the control
            textData.CreateControl();

            isHidingCaret = false;
            firstVisible = 0;
            blinkTime = NativeMethods.GetCaretBlinkTime() * 0.001f;
            lastBlink = FrameworkTimer.GetAbsoluteTime();
            textColor = new ColorValue(0.06f, 0.06f, 0.06f, 1.0f);
            selectedTextColor = new ColorValue(1.0f, 1.0f, 1.0f, 1.0f);
            selectedBackColor = new ColorValue(0.15f, 0.196f, 0.36f, 1.0f);
            caretColor = new ColorValue(0, 0, 0, 1.0f);
            caretPosition = textData.SelectionStart = 0;
            isInsertMode = true;
            isMouseDragging = false;
        }

        /// <summary>Set the caret to a character position, and adjust the scrolling if necessary</summary>
        protected void PlaceCaret(int pos)
        {
            // Store caret position
            caretPosition = pos;

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

            // if the new position is smaller than the first visible char 
            // we'll need to scroll
            if (firstVisible > caretPosition)
                firstVisible = caretPosition;
        }

        /// <summary>Clears the edit box</summary>
        public void Clear()
        {
            textData.Text = string.Empty;
            PlaceCaret(0);
            textData.SelectionStart = 0;
        }
        /// <summary>Sets the text for the control</summary>
        public void SetText(string text, bool selected)
        {
            if (text == null)
                text = string.Empty;

            textData.Text = text;
            textData.SelectionStart = text.Length;
            // Move the care to the end of the text
            PlaceCaret(text.Length);
            textData.SelectionStart = (selected) ? 0 : caretPosition;
            FocusText();
        }
        /// <summary>Deletes the text that is currently selected</summary>
        protected void DeleteSelectionText()
        {
            int first = Math.Min(caretPosition, textData.SelectionStart);
            int last = Math.Max(caretPosition, textData.SelectionStart);
            // Update caret and selection
            PlaceCaret(first);
            // Remove the characters
            textData.Text = textData.Text.Remove(first, (last-first));
            textData.SelectionStart = caretPosition;
            FocusText();
        }
        /// <summary>Updates the rectangles used by the control</summary>
        protected override void UpdateRectangles()
        {
            // Get the bounding box first
            base.UpdateRectangles ();

            // Update text rect
            textRect = boundingBox;
            // First inflate by border to compute render rects
            textRect.Inflate(-border, -border);
            
            // Update the render rectangles
            elementRects[0] = textRect;
            elementRects[1] = new System.Drawing.Rectangle(boundingBox.Left, boundingBox.Top, (textRect.Left - boundingBox.Left), (textRect.Top - boundingBox.Top));
            elementRects[2] = new System.Drawing.Rectangle(textRect.Left, boundingBox.Top, textRect.Width, (textRect.Top - boundingBox.Top));
            elementRects[3] = new System.Drawing.Rectangle(textRect.Right, boundingBox.Top, (boundingBox.Right - textRect.Right), (textRect.Top - boundingBox.Top));
            elementRects[4] = new System.Drawing.Rectangle(boundingBox.Left, textRect.Top, (textRect.Left - boundingBox.Left), textRect.Height);
            elementRects[5] = new System.Drawing.Rectangle(textRect.Right, textRect.Top, (boundingBox.Right - textRect.Right), textRect.Height);
            elementRects[6] = new System.Drawing.Rectangle(boundingBox.Left, textRect.Bottom, (textRect.Left - boundingBox.Left), (boundingBox.Bottom - textRect.Bottom));
            elementRects[7] = new System.Drawing.Rectangle(textRect.Left, textRect.Bottom, textRect.Width, (boundingBox.Bottom - textRect.Bottom));
            elementRects[8] = new System.Drawing.Rectangle(textRect.Right, textRect.Bottom, (boundingBox.Right - textRect.Right), (boundingBox.Bottom - textRect.Bottom));            

            // Inflate further by spacing
            textRect.Inflate(-spacing, -spacing);

            // Make the underlying rich text box the same size
            textData.Size = textRect.Size;
        }

        /// <summary>Copy the selected text to the clipboard</summary>
        protected void CopyToClipboard()
        {
            // Copy the selection text to the clipboard
            if (caretPosition != textData.SelectionStart)
            {
                int first = Math.Min(caretPosition, textData.SelectionStart);
                int last = Math.Max(caretPosition, textData.SelectionStart);
                // Set the text to the clipboard
                System.Windows.Forms.Clipboard.SetDataObject(textData.Text.Substring(first, (last-first)));
            }

        }
        /// <summary>Paste the clipboard data to the control</summary>
        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
                textData.Text = textData.Text.Insert(caretPosition, clipString);
                caretPosition += clipString.Length;
                textData.SelectionStart = caretPosition;
                FocusText();
            }
        }
        /// <summary>Reset's the caret blink time</summary>
        protected void ResetCaretBlink()
        {
            isCaretOn = true;
            lastBlink = FrameworkTimer.GetAbsoluteTime();
        }

        /// <summary>Update the caret when focus is in</summary>
        public override void OnFocusIn()
        {
            base.OnFocusIn();
            ResetCaretBlink();
        }

        /// <summary>Updates focus to the backing rich textbox so it updates it's state</summary>
        private void FocusText()
        {
            // Because of a design issue with the rich text box control that is used as 
            // the backing store for this control, the 'scrolling' mechanism built into
            // the control will only work if the control has focus.  Setting focus to the 
            // control here would work, but would cause a bad 'flicker' of the application.

            // Therefore, the automatic horizontal scrolling is turned off by default.  To 
            // enable it turn this define on.
#if (SCROLL_CORRECTLY)
            NativeMethods.SetFocus(textData.Handle);
            NativeMethods.SetFocus(Parent.SampleFramework.Window);
#endif
        }

        /// <summary>Handle keyboard input to the edit box</summary>
        public override bool HandleKeyboard(Microsoft.Samples.DirectX.UtilityToolkit.NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            // Default to not handling the message
            bool isHandled = false;
            if (msg == NativeMethods.WindowMessage.KeyDown)
            {
                switch((System.Windows.Forms.Keys)wParam.ToInt32())
                {
                    case System.Windows.Forms.Keys.End:
                    case System.Windows.Forms.Keys.Home:
                        // Move the caret
                        if (wParam.ToInt32() == (int)System.Windows.Forms.Keys.End)
                            PlaceCaret(textData.Text.Length);
                        else
                            PlaceCaret(0);
                        if (!NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
                        {
                            // Shift is not down. Update selection start along with caret
                            textData.SelectionStart = caretPosition;
                            FocusText();
                        }

                        ResetCaretBlink();
                        isHandled = true;
                        break;
                    case System.Windows.Forms.Keys.Insert:
                        if (NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ControlKey))
                        {
                            // Control insert -> Copy to clipboard
                            CopyToClipboard();
                        }
                        else if (NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
                        {
                            // Shift insert -> Paste from clipboard
                            PasteFromClipboard();
                        }
                        else
                        {
                            // Toggle insert mode
                            isInsertMode = !isInsertMode;
                        }
                        break;
                    case System.Windows.Forms.Keys.Delete:
                        // Check to see if there is a text selection
                        if (caretPosition != textData.SelectionStart)
                        {
                            DeleteSelectionText();
                            RaiseChangedEvent(this, true);
                        }
                        else
                        {
                            if (caretPosition < textData.Text.Length)
                            {
                                // Deleting one character
                                textData.Text = textData.Text.Remove(caretPosition, 1);
                                RaiseChangedEvent(this, true);
                            }
                        }
                        ResetCaretBlink();
                        isHandled = true;
                        break;

                    case System.Windows.Forms.Keys.Left:
                        if (NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ControlKey))
                        {
                            // Control is down. Move the caret to a new item
                            // instead of a character.
                        }
                        else if (caretPosition > 0)
                            PlaceCaret(caretPosition - 1); // Move one to the left

                        if (!NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
                        {
                            // Shift is not down. Update selection
                            // start along with the caret.
                            textData.SelectionStart = caretPosition;
                            FocusText();
                        }
                        ResetCaretBlink();
                        isHandled = true;
                        break;

                    case System.Windows.Forms.Keys.Right:
                        if (NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ControlKey))
                        {
                            // Control is down. Move the caret to a new item
                            // instead of a character.
                        }
                        else if (caretPosition < textData.Text.Length)
                            PlaceCaret(caretPosition + 1); // Move one to the left
                        if (!NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
                        {
                            // Shift is not down. Update selection
                            // start along with the caret.
                            textData.SelectionStart = caretPosition;
                            FocusText();
                        }
                        ResetCaretBlink();
                        isHandled = true;
                        break;

                    case System.Windows.Forms.Keys.Up:
                    case System.Windows.Forms.Keys.Down:
                        // Trap up and down arrows so that the dialog
                        // does not switch focus to another control.
                        isHandled = true;
                        break;

                    default:
                        // Let the application handle escape
                        isHandled = ((System.Windows.Forms.Keys)wParam.ToInt32()) == System.Windows.Forms.Keys.Escape;
                        break;
                }
            }

            return isHandled;
        }

        /// <summary>Handle mouse messages</summary>
        public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            // We need a new point
            System.Drawing.Point p = pt;
            p.X -= textRect.Left;
            p.Y -= textRect.Top;

            switch(msg)
            {
                case NativeMethods.WindowMessage.LeftButtonDown:
                case NativeMethods.WindowMessage.LeftButtonDoubleClick:
                    // Get focus first
                    if (!hasFocus)
                        Dialog.RequestFocus(this);

                    if (!ContainsPoint(pt))
                        return false;

                    isMouseDragging = true;
                    Parent.SampleFramework.Window.Capture = true;
                    // Determine the character corresponding to the coordinates
                    int index = textData.GetCharIndexFromPosition(p);

                    System.Drawing.Point startPosition = textData.GetPositionFromCharIndex(index);

                    if (p.X > startPosition.X && index < textData.Text.Length)
                        PlaceCaret(index + 1);
                    else
                        PlaceCaret(index);
                    
                    textData.SelectionStart = caretPosition;
                    FocusText();
                    ResetCaretBlink();
                    return true;

                case NativeMethods.WindowMessage.LeftButtonUp:
                    Parent.SampleFramework.Window.Capture = false;
                    isMouseDragging = false;
                    break;
                case NativeMethods.WindowMessage.MouseMove:
                    if (isMouseDragging)
                    {
                        // Determine the character corresponding to the coordinates
                        int dragIndex = textData.GetCharIndexFromPosition(p);

                        if (dragIndex < textData.Text.Length)
                            PlaceCaret(dragIndex + 1);
                        else
                            PlaceCaret(dragIndex);
                    }
                    break;
            }
            return false;
        }

        /// <summary>Handle all other messages</summary>
        public override bool MsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
        {
            if (!IsEnabled || !IsVisible)
                return false;

            if (msg == NativeMethods.WindowMessage.Character)
            {
                int charKey = wParam.ToInt32();
                switch(charKey)
                {
                    case (int)System.Windows.Forms.Keys.Back:
                    {
                        // If there's a selection, treat this
                        // like a delete key.
                        if (caretPosition != textData.SelectionStart)
                        {
                            DeleteSelectionText();
                            RaiseChangedEvent(this, true);
                        }
                        else if (caretPosition > 0)
                        {
                            // Move the caret and delete the char
                            textData.Text = textData.Text.Remove(caretPosition - 1, 1);
                            PlaceCaret(caretPosition - 1);
                            textData.SelectionStart = caretPosition;
                            FocusText();
                            RaiseChangedEvent(this, true);
                        }

                        ResetCaretBlink();
                        break;
                    }
                    case 24: // Ctrl-X Cut
                    case (int)System.Windows.Forms.Keys.Cancel: // Ctrl-C Copy
                    {
                        CopyToClipboard();

                        // If the key is Ctrl-X, delete the selection too.
                        if (charKey == 24)
                        {
                            DeleteSelectionText();
                            RaiseChangedEvent(this, true);
                        }

                        break;
                    }

                    // Ctrl-V Paste
                    case 22:
                    {
                        PasteFromClipboard();
                        RaiseChangedEvent(this, true);
                        break;
                    }
                    case (int)System.Windows.Forms.Keys.Return:
                        // Invoke the event when the user presses Enter.
                        RaiseEnterEvent(this, true);
                        break;

                    // Ctrl-A Select All
                    case 1:
                    {
                        if (textData.SelectionStart == caretPosition)
                        {
                            textData.SelectionStart = 0;
                            PlaceCaret(textData.Text.Length);
                        }
                        break;
                    }

                    // Junk characters we don't want in the string
                    case 26:  // Ctrl Z
                    case 2:   // Ctrl B
                    case 14:  // Ctrl N
                    case 19:  // Ctrl S
                    case 4:   // Ctrl D
                    case 6:   // Ctrl F
                    case 7:   // Ctrl G
                    case 10:  // Ctrl J
                    case 11:  // Ctrl K
                    case 12:  // Ctrl L
                    case 17:  // Ctrl Q
                    case 23:  // Ctrl W
                    case 5:   // Ctrl E
                    case 18:  // Ctrl R
                    case 20:  // Ctrl T
                    case 25:  // Ctrl Y
                    case 21:  // Ctrl U
                    case 9:   // Ctrl I
                    case 15:  // Ctrl O
                    case 16:  // Ctrl P
                    case 27:  // Ctrl [
                    case 29:  // Ctrl ]
                    case 28:  // Ctrl \ 
                        break;
                    
                    default:
                    {
                        // If there's a selection and the user
                        // starts to type, the selection should
                        // be deleted.
                        if (caretPosition != textData.SelectionStart)
                        {
                            DeleteSelectionText();
                        }
                        // If we are in overwrite mode and there is already
                        // a char at the caret's position, simply replace it.
                        // Otherwise, we insert the char as normal.
                        if (!isInsertMode && caretPosition < textData.Text.Length)
                        {
                            // This isn't the most efficient way to do this, but it's simple
                            // and shows the correct behavior
                            char[] charData = textData.Text.ToCharArray();
                            charData[caretPosition] = (char)wParam.ToInt32();
                            textData.Text = new string(charData);
                        }
                        else
                        {
                            // Insert the char
                            char c = (char)wParam.ToInt32();
                            textData.Text = textData.Text.Insert(caretPosition, c.ToString());
                        }

                        // Move the caret and selection position now
                        PlaceCaret(caretPosition + 1);
                        textData.SelectionStart = caretPosition;
                        FocusText();

                        ResetCaretBlink();
                        RaiseChangedEvent(this, true);
                        break;
                    }
                }
            }
            return false;
        }


        /// <summary>Render the control</summary>
        public override void Render(Device device, float elapsedTime)
        {
            if (!IsVisible)
                return; // Nothing to render

            // Render the control graphics
            for (int i = 0; i <= LowerRightBorder; ++i)
            {
                Element e = elementList[i] as Element;
                e.TextureColor.Blend(ControlState.Normal,elapsedTime);
                parentDialog.DrawSprite(e, elementRects[i]);
            }
            //
            // Compute the X coordinates of the first visible character.
            //
            int xFirst = textData.GetPositionFromCharIndex(firstVisible).X;
            int xCaret = textData.GetPositionFromCharIndex(caretPosition).X;
            int xSel;

            if (caretPosition != textData.SelectionStart)
                xSel = textData.GetPositionFromCharIndex(textData.SelectionStart).X;
            else
                xSel = xCaret;

            // Render the selection rectangle
            System.Drawing.Rectangle selRect = System.Drawing.Rectangle.Empty;
            if (caretPosition != textData.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, textRect.Top, selRight, textRect.Bottom);
                selRect.Offset(textRect.Left - xFirst, 0);
                selRect.Intersect(textRect);
                Parent.DrawRectangle(selRect, selectedBackColor);
            }

            // Render the text
            Element textElement = elementList[TextLayer] as Element;
            textElement.FontColor.Current = textColor;
            parentDialog.DrawText(textData.Text.Substring(firstVisible), textElement, textRect);
            
            // Render the selected text
            if (caretPosition != textData.SelectionStart)
            {
                int firstToRender = Math.Max(firstVisible, Math.Min(textData.SelectionStart, caretPosition));
                int numToRender = Math.Max(textData.SelectionStart, caretPosition) - firstToRender;
                textElement.FontColor.Current = selectedTextColor;
                parentDialog.DrawText(textData.Text.Substring(firstToRender, numToRender), textElement, selRect);
            }

            //
            // Blink the caret
            //
            if(FrameworkTimer.GetAbsoluteTime() - lastBlink >= blinkTime)
            {
                isCaretOn = !isCaretOn;
                lastBlink = FrameworkTimer.GetAbsoluteTime();
            }

            //
            // Render the caret if this control has the focus
            //
            if( hasFocus && isCaretOn && !isHidingCaret )
            {
                // Start the rectangle with insert mode caret
                System.Drawing.Rectangle caretRect = textRect;
                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 (!isInsertMode)
                {
                    // Obtain the X coord of the current character
                    caretRect.Width = 4;
                }

                parentDialog.DrawRectangle(caretRect, caretColor);
            }

        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer Universidad Tecnológica Nacional
Argentina Argentina
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions