home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Common / dxmutgui.cs < prev    next >
Encoding:
Text File  |  2004-09-27  |  207.5 KB  |  5,138 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: DXMUTGui.cs
  3. //
  4. // DirectX SDK Managed Direct3D GUI Sample Code
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. using System;
  9. using System.Collections;
  10. using Microsoft.DirectX;
  11. using Microsoft.DirectX.Direct3D;
  12.  
  13. namespace Microsoft.Samples.DirectX.UtilityToolkit
  14. {
  15.     /// <summary>
  16.     /// Predefined control types
  17.     /// </summary>
  18.     public enum ControlType
  19.     {
  20.         StaticText,
  21.         Button,
  22.         CheckBox,
  23.         RadioButton,
  24.         ComboBox,
  25.         Slider,
  26.         ListBox,
  27.         EditBox,
  28.         Scrollbar,
  29.     }
  30.  
  31.     /// <summary>
  32.     /// Possible states of a control
  33.     /// </summary>
  34.     public enum ControlState
  35.     {
  36.         Normal,
  37.         Disabled,
  38.         Hidden,
  39.         Focus,
  40.         MouseOver,
  41.         Pressed,
  42.         LastState // Should always be last
  43.     }
  44.  
  45.     /// <summary>
  46.     /// Blends colors
  47.     /// </summary>
  48.     public struct BlendColor
  49.     {
  50.         public ColorValue[] States; // Modulate colors for all possible control states
  51.         public ColorValue Current; // Current color
  52.  
  53.         /// <summary>Initialize the color blending</summary>
  54.         public void Initialize(ColorValue defaultColor, ColorValue disabledColor, ColorValue hiddenColor)
  55.         {
  56.             // Create the array
  57.             States = new ColorValue[(int)ControlState.LastState];
  58.             for(int i = 0; i < States.Length; i++)
  59.             {
  60.                 States[i] = defaultColor;
  61.             }
  62.  
  63.             // Store the data
  64.             States[(int)ControlState.Disabled] = disabledColor;
  65.             States[(int)ControlState.Hidden] = hiddenColor;
  66.             Current = hiddenColor;
  67.         }
  68.         /// <summary>Initialize the color blending</summary>
  69.         public void Initialize(ColorValue defaultColor) { Initialize( defaultColor, new ColorValue(0.5f, 0.5f, 0.5f, 0.75f),new ColorValue()); }
  70.  
  71.         /// <summary>Blend the colors together</summary>
  72.         public void Blend(ControlState state, float elapsedTime, float rate)
  73.         {
  74.             if ((States == null) || (States.Length == 0) )
  75.                 return; // Nothing to do
  76.  
  77.             ColorValue destColor = States[(int)state];
  78.             Current = ColorOperator.Lerp(Current, destColor, 1.0f - (float)Math.Pow(rate, 30 * elapsedTime) );
  79.         }
  80.         /// <summary>Blend the colors together</summary>
  81.         public void Blend(ControlState state, float elapsedTime) { Blend(state, elapsedTime, 0.7f); }
  82.     }
  83.  
  84.     /// <summary>
  85.     /// Contains all the display information for a given control type
  86.     /// </summary>
  87.     public struct ElementHolder
  88.     {
  89.         public ControlType ControlType;
  90.         public uint ElementIndex;
  91.         public Element Element;
  92.     }
  93.  
  94.     /// <summary>
  95.     /// Contains all the display tweakables for a sub-control
  96.     /// </summary>
  97.     public class Element : ICloneable
  98.     {
  99.         #region Magic Numbers
  100.         #endregion
  101.  
  102.         #region Instance Data
  103.         public uint TextureIndex; // Index of the texture for this Element 
  104.         public uint FontIndex; // Index of the font for this Element 
  105.         public DrawTextFormat textFormat; // The Format argument to draw text
  106.  
  107.         public System.Drawing.Rectangle textureRect; // Bounding rectangle of this element on the composite texture
  108.  
  109.         public BlendColor TextureColor;
  110.         public BlendColor FontColor;
  111.         #endregion
  112.  
  113.         /// <summary>Set the texture</summary>
  114.         public void SetTexture(uint tex, System.Drawing.Rectangle texRect, ColorValue defaultTextureColor)
  115.         {
  116.             // Store data
  117.             TextureIndex = tex;
  118.             textureRect = texRect;
  119.             TextureColor.Initialize(defaultTextureColor);
  120.         }
  121.         /// <summary>Set the texture</summary>
  122.         public void SetTexture(uint tex, System.Drawing.Rectangle texRect) { SetTexture(tex, texRect, Dialog.WhiteColorValue); }
  123.         /// <summary>Set the font</summary>
  124.         public void SetFont(uint font, ColorValue defaultFontColor, DrawTextFormat format)
  125.         {
  126.             // Store data
  127.             FontIndex = font;
  128.             textFormat = format;
  129.             FontColor.Initialize(defaultFontColor);
  130.         }
  131.         /// <summary>Set the font</summary>
  132.         public void SetFont(uint font){ SetFont(font, Dialog.WhiteColorValue, DrawTextFormat.Center | DrawTextFormat.VerticalCenter ); }
  133.         /// <summary>
  134.         /// Refresh this element
  135.         /// </summary>
  136.         public void Refresh()
  137.         {
  138.             if (TextureColor.States != null) 
  139.                 TextureColor.Current = TextureColor.States[(int)ControlState.Hidden];
  140.             if (FontColor.States != null) 
  141.                 FontColor.Current = FontColor.States[(int)ControlState.Hidden];
  142.         }
  143.  
  144.         #region ICloneable Members
  145.         /// <summary>Clone an object</summary>
  146.         public Element Clone() 
  147.         { 
  148.             Element e = new Element();
  149.             e.TextureIndex = this.TextureIndex;
  150.             e.FontIndex = this.FontIndex;
  151.             e.textFormat = this.textFormat;
  152.             e.textureRect = this.textureRect; 
  153.             e.TextureColor = this.TextureColor;
  154.             e.FontColor = this.FontColor;
  155.  
  156.             return e;
  157.         }
  158.         /// <summary>Clone an object</summary>
  159.         object ICloneable.Clone() { throw new NotSupportedException("Use the strongly typed clone.");}
  160.  
  161.         #endregion
  162.     }
  163.  
  164.  
  165.     #region Dialog Resource Manager
  166.     /// <summary>
  167.     /// Structure for shared textures
  168.     /// </summary>
  169.     public class TextureNode 
  170.     {
  171.         public string Filename;
  172.         public Texture Texture;
  173.         public uint Width;
  174.         public uint Height;
  175.     }
  176.  
  177.     /// <summary>
  178.     /// Structure for shared fonts
  179.     /// </summary>
  180.     public class FontNode 
  181.     {
  182.         public string FaceName;
  183.         public Font Font;
  184.         public uint Height;
  185.         public FontWeight Weight;
  186.     }
  187.  
  188.     /// <summary>
  189.     /// Manages shared resources of dialogs
  190.     /// </summary>
  191.     public sealed class DialogResourceManager
  192.     {
  193.         private StateBlock dialogStateBlock;  // Stateblock shared amongst all dialogs
  194.         private Sprite dialogSprite; // Sprite used for drawing
  195.         public StateBlock StateBlock { get { return dialogStateBlock; } }
  196.         public Sprite Sprite { get { return dialogSprite; } }
  197.         private Device device; // Device
  198.  
  199.         // Lists of textures/fonts
  200.         private ArrayList textureCache = new ArrayList();
  201.         private ArrayList fontCache = new ArrayList();
  202.  
  203.         #region Creation
  204.         /// <summary>Do not allow creation</summary>
  205.         private DialogResourceManager()  {
  206.             device = null;
  207.             dialogSprite = null;
  208.             dialogStateBlock = null;
  209.         } 
  210.  
  211.         private static DialogResourceManager localObject = null;
  212.         public static DialogResourceManager GetGlobalInstance()
  213.         {
  214.             if (localObject == null)
  215.                 localObject = new DialogResourceManager();
  216.  
  217.             return localObject;
  218.         }
  219.         #endregion
  220.  
  221.         /// <summary>Gets a font node from the cache</summary>
  222.         public FontNode GetFontNode(int index) { return fontCache[index] as FontNode; }
  223.         /// <summary>Gets a texture node from the cache</summary>
  224.         public TextureNode GetTextureNode(int index) { return textureCache[index] as TextureNode; }
  225.         /// <summary>Gets the device</summary>
  226.         public Device Device { get { return device; } }
  227.  
  228.         /// <summary>
  229.         /// Adds a font to the resource manager
  230.         /// </summary>
  231.         public int AddFont(string faceName, uint height, FontWeight weight)
  232.         {
  233.             // See if this font exists
  234.             for(int i = 0; i < fontCache.Count; i++)
  235.             {
  236.                 FontNode fn = fontCache[i] as FontNode;
  237.                 if ( (string.Compare(fn.FaceName, faceName, true) == 0) &&
  238.                     fn.Height == height &&
  239.                     fn.Weight == weight)
  240.                 {
  241.                     // Found it
  242.                     return i;
  243.                 }
  244.             }
  245.  
  246.             // Doesn't exist, add a new one and try to create it
  247.             FontNode newNode = new FontNode();
  248.             newNode.FaceName = faceName;
  249.             newNode.Height = height;
  250.             newNode.Weight = weight;
  251.             fontCache.Add(newNode);
  252.  
  253.             int fontIndex = fontCache.Count-1;
  254.             // If a device is available, try to create immediately
  255.             if (device != null)
  256.                 CreateFont(fontIndex);
  257.  
  258.             return fontIndex;
  259.         }
  260.         /// <summary>
  261.         /// Adds a texture to the resource manager
  262.         /// </summary>
  263.         public int AddTexture(string filename)
  264.         {
  265.             // See if this font exists
  266.             for(int i = 0; i < textureCache.Count; i++)
  267.             {
  268.                 TextureNode tn = textureCache[i] as TextureNode;
  269.                 if (string.Compare(tn.Filename, filename, true) == 0)
  270.                 {
  271.                     // Found it
  272.                     return i;
  273.                 }
  274.             }
  275.             // Doesn't exist, add a new one and try to create it
  276.             TextureNode newNode = new TextureNode();
  277.             newNode.Filename = filename;
  278.             textureCache.Add(newNode);
  279.  
  280.             int texIndex = textureCache.Count-1;
  281.  
  282.             // If a device is available, try to create immediately
  283.             if (device != null)
  284.                 CreateTexture(texIndex);
  285.  
  286.             return texIndex;
  287.  
  288.         }
  289.  
  290.         /// <summary>
  291.         /// Creates a font
  292.         /// </summary>
  293.         public void CreateFont(int font)
  294.         {
  295.             // Get the font node here
  296.             FontNode fn = GetFontNode(font);
  297.             if (fn.Font != null)
  298.                 fn.Font.Dispose(); // Get rid of this
  299.  
  300.             // Create the new font
  301.             fn.Font = new Font(device, (int)fn.Height, 0, fn.Weight, 1, false, CharacterSet.Default,
  302.                 Precision.Default, FontQuality.Default, PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare,
  303.                 fn.FaceName);
  304.         }
  305.  
  306.         /// <summary>
  307.         /// Creates a texture
  308.         /// </summary>
  309.         public void CreateTexture(int tex)
  310.         {
  311.             // Get the texture node here
  312.             TextureNode tn = GetTextureNode(tex);
  313.  
  314.             // Make sure there's a texture to create
  315.             if ((tn.Filename == null) || (tn.Filename.Length == 0))
  316.                 return;
  317.  
  318.             // Find the texture
  319.             string path = Utility.FindMediaFile(tn.Filename);
  320.  
  321.             // Create the new texture
  322.             ImageInformation info = new ImageInformation();
  323.             tn.Texture = TextureLoader.FromFile(device, path, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None,
  324.                 Format.Unknown, Pool.Managed, (Filter)D3DX.Default, (Filter)D3DX.Default, 0, ref info);
  325.  
  326.             // Store dimensions
  327.             tn.Width = (uint)info.Width;
  328.             tn.Height = (uint)info.Height;
  329.  
  330.         }
  331.  
  332.         #region Device event callbacks
  333.         /// <summary>
  334.         /// Called when the device is created
  335.         /// </summary>
  336.         public void OnCreateDevice(Device d) 
  337.         {
  338.             // Store device
  339.             device = d;
  340.  
  341.             // create fonts and textures
  342.             for (int i = 0; i < fontCache.Count; i++)
  343.                 CreateFont(i);
  344.  
  345.             for (int i = 0; i < textureCache.Count; i++)
  346.                 CreateTexture(i);
  347.  
  348.             dialogSprite = new Sprite(d); // Create the sprite
  349.         } 
  350.         /// <summary>
  351.         /// Called when the device is reset
  352.         /// </summary>
  353.         public void OnResetDevice(Device device)
  354.         {
  355.             foreach(FontNode fn in fontCache)
  356.                 fn.Font.OnResetDevice();
  357.  
  358.             if (dialogSprite != null)
  359.                 dialogSprite.OnResetDevice();
  360.             
  361.             // Create new state block
  362.             dialogStateBlock = new StateBlock(device, StateBlockType.All);
  363.         }
  364.  
  365.         /// <summary>
  366.         /// Clear any resources that need to be lost
  367.         /// </summary>
  368.         public void OnLostDevice()
  369.         {
  370.             foreach(FontNode fn in fontCache)
  371.             {
  372.                 if ( (fn.Font != null) && (!fn.Font.Disposed) )
  373.                     fn.Font.OnLostDevice();
  374.             }
  375.  
  376.             if (dialogSprite != null)
  377.                 dialogSprite.OnLostDevice();
  378.  
  379.             if (dialogStateBlock != null)
  380.             {
  381.                 dialogStateBlock.Dispose();
  382.                 dialogStateBlock = null;
  383.             }
  384.         }
  385.         
  386.         /// <summary>
  387.         /// Destroy any resources and clear the caches
  388.         /// </summary>
  389.         public void OnDestroyDevice()
  390.         {
  391.             foreach(FontNode fn in fontCache)
  392.                 fn.Font.Dispose();
  393.             
  394.             foreach(TextureNode tn in textureCache)
  395.                 tn.Texture.Dispose();
  396.  
  397.             if (dialogSprite != null)
  398.             {
  399.                 dialogSprite.Dispose();
  400.                 dialogSprite = null;
  401.             }
  402.  
  403.             if (dialogStateBlock != null)
  404.             {
  405.                 dialogStateBlock.Dispose();
  406.                 dialogStateBlock = null;
  407.             }
  408.         }
  409.  
  410.         #endregion
  411.     }
  412.  
  413.     #endregion
  414.  
  415.     /// <summary>
  416.     /// All controls must be assigned to a dialog, which handles
  417.     /// input and rendering for the controls.
  418.     /// </summary>
  419.     public class Dialog
  420.     {
  421.         #region Static Data
  422.         public const int WheelDelta = 120;
  423.         public static readonly ColorValue WhiteColorValue = new ColorValue(1.0f, 1.0f, 1.0f, 1.0f); 
  424.         public static readonly ColorValue TransparentWhite = new ColorValue(1.0f, 1.0f, 1.0f, 0.0f); 
  425.         public static readonly ColorValue BlackColorValue = new ColorValue(0.0f, 0.0f, 0.0f, 1.0f); 
  426.         private static Control controlFocus = null; // The control which has focus
  427.         private static Control controlMouseOver = null; // The control which is hovered over
  428.         private static Control controlMouseDown = null; // The control which the mouse was pressed on
  429.  
  430.         private static double timeRefresh = 0.0;
  431.         /// <summary>Set the static refresh time</summary>
  432.         public static void SetRefreshTime(float time) { timeRefresh = time; }
  433.         #endregion
  434.  
  435.         #region Instance Data
  436.         // Sample framework
  437.         private Framework parent = null; 
  438.         public Framework SampleFramework { get { return parent; } }
  439.  
  440.         // Vertex information
  441.         private CustomVertex.TransformedColoredTextured[] vertices;
  442.  
  443.         // Timing
  444.         private double timeLastRefresh;
  445.  
  446.         // Control/Elements
  447.         private ArrayList controlList = new ArrayList();
  448.         private ArrayList defaultElementList = new ArrayList();
  449.  
  450.         // Captions
  451.         private bool hasCaption;
  452.         private string caption;
  453.         private int captionHeight;
  454.         private Element captionElement;
  455.         private bool isDialogMinimized;
  456.  
  457.         // Dialog information
  458.         private int dialogX, dialogY, width, height;
  459.         // Colors
  460.         private ColorValue topLeftColor, topRightColor, bottomLeftColor, bottomRightColor;
  461.         
  462.         // Fonts/Textures
  463.         private ArrayList textureList = new ArrayList(); // Index into texture cache
  464.         private ArrayList fontList = new ArrayList(); // Index into font cache
  465.  
  466.         // Dialogs
  467.         private Dialog nextDialog;
  468.         private Dialog prevDialog;
  469.  
  470.         // User Input control
  471.         private bool usingNonUserEvents;
  472.         private bool usingKeyboardInput;
  473.         private bool usingMouseInput;
  474.         #endregion
  475.  
  476.         #region Simple Properties/Methods
  477.         /// <summary>Is the dilaog using non user events</summary>
  478.         public bool IsUsingNonUserEvents { get { return usingNonUserEvents; } set { usingNonUserEvents = value; } }
  479.         /// <summary>Is the dilaog using keyboard input</summary>
  480.         public bool IsUsingKeyboardInput { get { return usingKeyboardInput; } set { usingKeyboardInput = value; } }
  481.         /// <summary>Is the dilaog using mouse input</summary>
  482.         public bool IsUsingMouseInput { get { return usingMouseInput; } set { usingMouseInput = value; } }
  483.         /// <summary>Is the dilaog minimized</summary>
  484.         public bool IsMinimized { get { return isDialogMinimized; } set { isDialogMinimized = value; } }
  485.         /// <summary>Called to set dialog's location</summary>
  486.         public void SetLocation(int x, int y) { dialogX = x; dialogY = y; UpdateVertices(); }
  487.         /// <summary>The dialog's location</summary>
  488.         public System.Drawing.Point Location { 
  489.             get {return new System.Drawing.Point(dialogX, dialogY); } 
  490.             set { dialogX = value.X; dialogY = value.Y; UpdateVertices(); } 
  491.         }
  492.  
  493.         /// <summary>Called to set dialog's size</summary>
  494.         public void SetSize(int w, int h) { width = w; height = h;}
  495.         /// <summary>Dialogs width</summary>
  496.         public int Width { get { return width; } set { width = value; } }
  497.         /// <summary>Dialogs height</summary>
  498.         public int Height { get { return height; } set { height = value; } }
  499.         /// <summary>Called to set dialog's caption</summary>
  500.         public void SetCaptionText(string text) { caption = text; }
  501.         /// <summary>The dialog's caption height</summary>
  502.         public int CaptionHeight { get { return captionHeight; } set { captionHeight = value; } }
  503.         /// <summary>Called to set dialog's caption enabled state</summary>
  504.         public void SetCaptionEnabled(bool isEnabled) { hasCaption = isEnabled; }
  505.         /// <summary>Called to set dialog's border colors</summary>
  506.         public void SetBackgroundColors(ColorValue topLeft, ColorValue topRight, ColorValue bottomLeft, ColorValue bottomRight) 
  507.         { 
  508.             topLeftColor = topLeft; topRightColor = topRight; bottomLeftColor = bottomLeft; bottomRightColor = bottomRight;
  509.             UpdateVertices();
  510.         }
  511.         /// <summary>Called to set dialog's border colors</summary>
  512.         public void SetBackgroundColors(ColorValue allCorners) { SetBackgroundColors(allCorners, allCorners, allCorners, allCorners); }
  513.  
  514.         #endregion
  515.  
  516.         /// <summary>
  517.         /// Create a new instance of the dialog class
  518.         /// </summary>
  519.         public Dialog(Framework sample)
  520.         {
  521.             parent = sample; // store this for later use
  522.             // Initialize to default state
  523.             dialogX = 0; dialogY = 0; width = 0; height = 0;
  524.             hasCaption = false; isDialogMinimized = false; 
  525.             caption = string.Empty;
  526.             captionHeight = 18;
  527.  
  528.             topLeftColor = topRightColor = bottomLeftColor = bottomRightColor = new ColorValue();
  529.  
  530.             timeLastRefresh = 0.0f;
  531.             
  532.             nextDialog = this; // Only one dialog
  533.             prevDialog = this;  // Only one dialog
  534.  
  535.             usingNonUserEvents = false;
  536.             usingKeyboardInput = false;
  537.             usingMouseInput = true;
  538.  
  539.             InitializeDefaultElements();
  540.         }
  541.  
  542.         /// <summary>
  543.         /// Initialize the default elements for this dialog
  544.         /// </summary>
  545.         private void InitializeDefaultElements()
  546.         {
  547.             SetTexture(0, "UI\\DXUTControls.dds");
  548.             SetFont(0, "Arial", 14, FontWeight.Normal);
  549.  
  550.             //-------------------------------------
  551.             // Element for the caption
  552.             //-------------------------------------
  553.             captionElement = new Element();
  554.             captionElement.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.VerticalCenter);
  555.             captionElement.SetTexture(0, new System.Drawing.Rectangle(17,269,224,18));
  556.             captionElement.TextureColor.States[(int)ControlState.Normal] = WhiteColorValue;
  557.             captionElement.FontColor.States[(int)ControlState.Normal] = WhiteColorValue;
  558.             // Pre-blend as we don't need to transition the state
  559.             captionElement.TextureColor.Blend(ControlState.Normal, 10.0f);
  560.             captionElement.FontColor.Blend(ControlState.Normal, 10.0f);
  561.  
  562.             Element e = new Element();
  563.  
  564.             //-------------------------------------
  565.             // StaticText
  566.             //-------------------------------------
  567.             e.SetFont(0);
  568.             e.FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.75f, 0.75f, 0.75f, 0.75f);
  569.             // Assign the element
  570.             SetDefaultElement(ControlType.StaticText, StaticText.TextElement, e);
  571.  
  572.             //-------------------------------------
  573.             // Button - Button
  574.             //-------------------------------------
  575.             e.SetTexture(0, new System.Drawing.Rectangle(0,0,136,54));
  576.             e.SetFont(0);
  577.             e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
  578.             e.TextureColor.States[(int)ControlState.Pressed] = new ColorValue(1.0f, 1.0f, 1.0f, 0.85f);
  579.             e.FontColor.States[(int)ControlState.MouseOver] = BlackColorValue;
  580.             // Assign the element
  581.             SetDefaultElement(ControlType.Button, Button.ButtonLayer, e);
  582.  
  583.             //-------------------------------------
  584.             // Button - Fill Layer
  585.             //-------------------------------------
  586.             e.SetTexture(0, new System.Drawing.Rectangle(136,0,136,54), TransparentWhite);
  587.             e.TextureColor.States[(int)ControlState.MouseOver] = new ColorValue(1.0f, 1.0f, 1.0f, 0.6f);
  588.             e.TextureColor.States[(int)ControlState.Pressed] = new ColorValue(0,0,0, 0.25f);
  589.             e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.05f);
  590.             // Assign the element
  591.             SetDefaultElement(ControlType.Button, Button.FillLayer, e);
  592.  
  593.  
  594.             //-------------------------------------
  595.             // CheckBox - Box
  596.             //-------------------------------------
  597.             e.SetTexture(0, new System.Drawing.Rectangle(0,54,27,27));
  598.             e.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.VerticalCenter);
  599.             e.FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.8f);
  600.             e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
  601.             e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.8f);
  602.             e.TextureColor.States[(int)ControlState.Pressed] = WhiteColorValue;
  603.             // Assign the element
  604.             SetDefaultElement(ControlType.CheckBox, Checkbox.BoxLayer, e);
  605.  
  606.             //-------------------------------------
  607.             // CheckBox - Check
  608.             //-------------------------------------
  609.             e.SetTexture(0, new System.Drawing.Rectangle(27,54,27,27));
  610.             // Assign the element
  611.             SetDefaultElement(ControlType.CheckBox, Checkbox.CheckLayer, e);
  612.  
  613.             //-------------------------------------
  614.             // RadioButton - Box
  615.             //-------------------------------------
  616.             e.SetTexture(0, new System.Drawing.Rectangle(54,54,27,27));
  617.             e.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.VerticalCenter);
  618.             e.FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.8f);
  619.             e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
  620.             e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.8f);
  621.             e.TextureColor.States[(int)ControlState.Pressed] = WhiteColorValue;
  622.             // Assign the element
  623.             SetDefaultElement(ControlType.RadioButton, RadioButton.BoxLayer, e);
  624.  
  625.             //-------------------------------------
  626.             // RadioButton - Check
  627.             //-------------------------------------
  628.             e.SetTexture(0, new System.Drawing.Rectangle(81,54,27,27));
  629.             // Assign the element
  630.             SetDefaultElement(ControlType.RadioButton, RadioButton.CheckLayer, e);
  631.  
  632.             //-------------------------------------
  633.             // ComboBox - Main
  634.             //-------------------------------------
  635.             e.SetTexture(0, new System.Drawing.Rectangle(7,81, 240, 42));
  636.             e.SetFont(0);
  637.             e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(0.8f, 0.8f, 0.8f, 0.55f);
  638.             e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(0.95f, 0.95f, 0.95f, 0.6f);
  639.             e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.25f);
  640.             e.FontColor.States[(int)ControlState.MouseOver] = new ColorValue(0,0,0,1.0f);
  641.             e.FontColor.States[(int)ControlState.Pressed] = new ColorValue(0,0,0,1.0f);
  642.             e.FontColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 0.8f);
  643.             // Assign the element
  644.             SetDefaultElement(ControlType.ComboBox, ComboBox.MainLayer, e);
  645.  
  646.             //-------------------------------------
  647.             // ComboBox - Button
  648.             //-------------------------------------
  649.             e.SetTexture(0, new System.Drawing.Rectangle(272,0, 53, 49));
  650.             e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
  651.             e.TextureColor.States[(int)ControlState.Pressed] = new ColorValue(0.55f, 0.55f, 0.55f, 1.0f);
  652.             e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.75f);
  653.             e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(1.0f, 1.0f, 1.0f, 0.25f);
  654.             // Assign the element
  655.             SetDefaultElement(ControlType.ComboBox, ComboBox.ComboButtonLayer, e);
  656.  
  657.             //-------------------------------------
  658.             // ComboBox - Dropdown
  659.             //-------------------------------------
  660.             e.SetTexture(0, new System.Drawing.Rectangle(7,123,234,142));
  661.             e.SetFont(0, BlackColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
  662.             // Assign the element
  663.             SetDefaultElement(ControlType.ComboBox, ComboBox.DropdownLayer, e);
  664.  
  665.             //-------------------------------------
  666.             // ComboBox - Selection
  667.             //-------------------------------------
  668.             e.SetTexture(0, new System.Drawing.Rectangle(7,266,234,23));
  669.             e.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
  670.             // Assign the element
  671.             SetDefaultElement(ControlType.ComboBox, ComboBox.SelectionLayer, e);
  672.  
  673.             //-------------------------------------
  674.             // Slider - Track
  675.             //-------------------------------------
  676.             e.SetTexture(0, new System.Drawing.Rectangle(1,290,279,41));
  677.             e.TextureColor.States[(int)ControlState.Normal] = new ColorValue(1.0f, 1.0f, 1.0f, 0.55f);
  678.             e.TextureColor.States[(int)ControlState.Focus] = new ColorValue(1.0f, 1.0f, 1.0f, 0.75f);
  679.             e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(1.0f, 1.0f, 1.0f, 0.25f);
  680.             // Assign the element
  681.             SetDefaultElement(ControlType.Slider, Slider.TrackLayer, e);
  682.  
  683.             //-------------------------------------
  684.             // Slider - Button
  685.             //-------------------------------------
  686.             e.SetTexture(0, new System.Drawing.Rectangle(248,55,41,41));
  687.             // Assign the element
  688.             SetDefaultElement(ControlType.Slider, Slider.ButtonLayer, e);
  689.  
  690.             //-------------------------------------
  691.             // Scrollbar - Track
  692.             //-------------------------------------
  693.             e.SetTexture(0, new System.Drawing.Rectangle(243,144,22,11));
  694.             // Assign the element
  695.             SetDefaultElement(ControlType.Scrollbar, ScrollBar.TrackLayer, e);
  696.  
  697.             //-------------------------------------
  698.             // Scrollbar - Up Arrow
  699.             //-------------------------------------
  700.             e.SetTexture(0, new System.Drawing.Rectangle(243,124,22,20));
  701.             e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 1.0f);
  702.             // Assign the element
  703.             SetDefaultElement(ControlType.Scrollbar, ScrollBar.UpButtonLayer, e);
  704.  
  705.             //-------------------------------------
  706.             // Scrollbar - Down Arrow
  707.             //-------------------------------------
  708.             e.SetTexture(0, new System.Drawing.Rectangle(243,155,22,21));
  709.             e.TextureColor.States[(int)ControlState.Disabled] = new ColorValue(0.8f, 0.8f, 0.8f, 1.0f);
  710.             // Assign the element
  711.             SetDefaultElement(ControlType.Scrollbar, ScrollBar.DownButtonLayer, e);
  712.  
  713.             //-------------------------------------
  714.             // Scrollbar - Button
  715.             //-------------------------------------
  716.             e.SetTexture(0, new System.Drawing.Rectangle(266,123,20,44));
  717.             // Assign the element
  718.             SetDefaultElement(ControlType.Scrollbar, ScrollBar.ThumbLayer, e);
  719.  
  720.  
  721.             //-------------------------------------
  722.             // EditBox
  723.             //-------------------------------------
  724.             // Element assignment:
  725.             //   0 - text area
  726.             //   1 - top left border
  727.             //   2 - top border
  728.             //   3 - top right border
  729.             //   4 - left border
  730.             //   5 - right border
  731.             //   6 - lower left border
  732.             //   7 - lower border
  733.             //   8 - lower right border
  734.             e.SetFont(0, BlackColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
  735.             
  736.             // Assign the styles
  737.             e.SetTexture(0, new System.Drawing.Rectangle(14,90,227,23));
  738.             SetDefaultElement(ControlType.EditBox, EditBox.TextLayer, e);
  739.             e.SetTexture(0, new System.Drawing.Rectangle(8,82,6,8));
  740.             SetDefaultElement(ControlType.EditBox, EditBox.TopLeftBorder, e);
  741.             e.SetTexture(0, new System.Drawing.Rectangle(14,82,227,8));
  742.             SetDefaultElement(ControlType.EditBox, EditBox.TopBorder, e);
  743.             e.SetTexture(0, new System.Drawing.Rectangle(241,82,5,8));
  744.             SetDefaultElement(ControlType.EditBox, EditBox.TopRightBorder, e);
  745.             e.SetTexture(0, new System.Drawing.Rectangle(8,90,6,23));
  746.             SetDefaultElement(ControlType.EditBox, EditBox.LeftBorder, e);
  747.             e.SetTexture(0, new System.Drawing.Rectangle(241,90,5,23));
  748.             SetDefaultElement(ControlType.EditBox, EditBox.RightBorder, e);
  749.             e.SetTexture(0, new System.Drawing.Rectangle(8,113,6,8));
  750.             SetDefaultElement(ControlType.EditBox, EditBox.LowerLeftBorder, e);
  751.             e.SetTexture(0, new System.Drawing.Rectangle(14,113,227,8));
  752.             SetDefaultElement(ControlType.EditBox, EditBox.LowerBorder, e);
  753.             e.SetTexture(0, new System.Drawing.Rectangle(241,113,5,8));
  754.             SetDefaultElement(ControlType.EditBox, EditBox.LowerRightBorder, e);
  755.  
  756.  
  757.             //-------------------------------------
  758.             // Listbox - Main
  759.             //-------------------------------------
  760.             e.SetTexture(0, new System.Drawing.Rectangle(13,124,228,141));
  761.             e.SetFont(0, BlackColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
  762.             // Assign the element
  763.             SetDefaultElement(ControlType.ListBox, ListBox.MainLayer, e);
  764.  
  765.             //-------------------------------------
  766.             // Listbox - Selection
  767.             //-------------------------------------
  768.             e.SetTexture(0, new System.Drawing.Rectangle(17,269,224,18));
  769.             e.SetFont(0, WhiteColorValue, DrawTextFormat.Left | DrawTextFormat.Top);
  770.             // Assign the element
  771.             SetDefaultElement(ControlType.ListBox, ListBox.SelectionLayer, e);
  772.         }
  773.  
  774.         /// <summary>Removes all controls from this dialog</summary>
  775.         public void RemoveAllControls()
  776.         {
  777.             controlList.Clear();
  778.             if ( (controlFocus != null) && (controlFocus.Parent == this) )
  779.                 controlFocus = null;
  780.             
  781.             controlMouseOver = null;
  782.         }
  783.  
  784.         /// <summary>Clears the radio button group</summary>
  785.         public void ClearRadioButtonGroup(uint groupIndex)
  786.         {
  787.             // Find all radio buttons with the given group number
  788.             foreach(Control c in controlList)
  789.             {
  790.                 if (c.ControlType == ControlType.RadioButton)
  791.                 {
  792.                     RadioButton rb = c as RadioButton;
  793.                     // Clear the radio button checked setting
  794.                     if (rb.ButtonGroup == groupIndex)
  795.                         rb.SetChecked(false, false);
  796.                 }
  797.             }
  798.         }
  799.  
  800.         /// <summary>Clears the combo box of all items</summary>
  801.         public void ClearComboBox(int id)
  802.         {
  803.             ComboBox comboBox = GetComboBox(id);
  804.             if (comboBox == null)
  805.                 return;
  806.  
  807.             comboBox.Clear();
  808.         }
  809.  
  810.         #region Message handling
  811.         private static bool isDragging;
  812.         /// <summary>
  813.         /// Handle messages for this dialog
  814.         /// </summary>
  815.         public bool MessageProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  816.         {
  817.             // If caption is enable, check for clicks in the caption area.
  818.             if (hasCaption)
  819.             {
  820.                 if (msg == NativeMethods.WindowMessage.LeftButtonDown || msg == NativeMethods.WindowMessage.LeftButtonDoubleClick)
  821.                 {
  822.                     // Current mouse position
  823.                     short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
  824.                     short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
  825.  
  826.                     if (mouseX >= dialogX && mouseX < dialogX + width && 
  827.                         mouseY >= dialogY && mouseY < dialogY + captionHeight)
  828.                     {
  829.                         isDragging = true;
  830.                         NativeMethods.SetCapture(hWnd);
  831.                         return true;
  832.                     }
  833.                 }
  834.                 else if ( (msg == NativeMethods.WindowMessage.LeftButtonUp) && isDragging)
  835.                 {
  836.                     // Current mouse position
  837.                     short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
  838.                     short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
  839.  
  840.                     if (mouseX >= dialogX && mouseX < dialogX + width && 
  841.                         mouseY >= dialogY && mouseY < dialogY + captionHeight)
  842.                     {
  843.                         NativeMethods.ReleaseCapture();
  844.                         isDragging = false;
  845.                         return true;
  846.                     }
  847.                 }
  848.             }
  849.             
  850.             // If the dialog is minimized, don't send any messages to controls.
  851.             if (isDialogMinimized)
  852.                 return false;
  853.  
  854.             // If a control is in focus, it belongs to this dialog, and it's enabled, then give
  855.             // it the first chance at handling the message.
  856.             if (controlFocus != null && 
  857.                 controlFocus.Parent == this && 
  858.                 controlFocus.IsEnabled)
  859.             {
  860.                 // If the control MsgProc handles it, then we don't.
  861.                 if (controlFocus.MsgProc(hWnd, msg, wParam, lParam))
  862.                     return true;
  863.             }
  864.  
  865.             switch(msg)
  866.             {
  867.                 // Call OnFocusIn()/OnFocusOut() of the control that currently has the focus
  868.                 // as the application is activated/deactivated.  This matches the Windows
  869.                 // behavior.
  870.                 case NativeMethods.WindowMessage.ActivateApplication:
  871.                 {
  872.                     if (controlFocus != null && 
  873.                         controlFocus.Parent == this && 
  874.                         controlFocus.IsEnabled)
  875.                     {
  876.                         if (wParam != IntPtr.Zero)
  877.                             controlFocus.OnFocusIn();
  878.                         else
  879.                             controlFocus.OnFocusOut();
  880.                     }
  881.                 }
  882.                     break;
  883.  
  884.                 // Keyboard messages
  885.                 case NativeMethods.WindowMessage.KeyDown:
  886.                 case NativeMethods.WindowMessage.SystemKeyDown:
  887.                 case NativeMethods.WindowMessage.KeyUp:
  888.                 case NativeMethods.WindowMessage.SystemKeyUp:
  889.                 {
  890.                     // If a control is in focus, it belongs to this dialog, and it's enabled, then give
  891.                     // it the first chance at handling the message.
  892.                     if (controlFocus != null && 
  893.                         controlFocus.Parent == this && 
  894.                         controlFocus.IsEnabled)
  895.                     {
  896.                         // If the control MsgProc handles it, then we don't.
  897.                         if (controlFocus.HandleKeyboard(msg, wParam, lParam))
  898.                             return true;
  899.                     }
  900.  
  901.                     // Not yet handled, see if this matches a control's hotkey
  902.                     if (msg == NativeMethods.WindowMessage.KeyUp)
  903.                     {
  904.                         foreach(Control c in controlList)
  905.                         {
  906.                             // Was the hotkey hit?
  907.                             if (c.Hotkey == (System.Windows.Forms.Keys)wParam.ToInt32())
  908.                             {
  909.                                 // Yup!
  910.                                 c.OnHotKey();
  911.                                 return true;
  912.                             }
  913.                         }
  914.                     }
  915.                     if (msg == NativeMethods.WindowMessage.KeyDown)
  916.                     {
  917.                         // If keyboard input is not enabled, this message should be ignored
  918.                         if (!usingKeyboardInput)
  919.                             return false;
  920.  
  921.                         System.Windows.Forms.Keys key = (System.Windows.Forms.Keys)wParam.ToInt32();
  922.                         switch(key)
  923.                         {
  924.                             case System.Windows.Forms.Keys.Right:
  925.                             case System.Windows.Forms.Keys.Down:
  926.                                 if (controlFocus != null)
  927.                                 {
  928.                                     OnCycleFocus(true);
  929.                                     return true;
  930.                                 }
  931.                                 break;
  932.                             case System.Windows.Forms.Keys.Left:
  933.                             case System.Windows.Forms.Keys.Up:
  934.                                 if (controlFocus != null)
  935.                                 {
  936.                                     OnCycleFocus(false);
  937.                                     return true;
  938.                                 }
  939.                                 break;
  940.                             case System.Windows.Forms.Keys.Tab:
  941.                                 if (controlFocus == null)
  942.                                 {
  943.                                     FocusDefaultControl();
  944.                                 }
  945.                                 else
  946.                                 {
  947.                                     bool shiftDown = NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey);
  948.  
  949.                                     OnCycleFocus(!shiftDown);
  950.                                 }
  951.                                 return true;
  952.                         }
  953.                     }
  954.                 }
  955.                     break;
  956.  
  957.                 // Mouse messages
  958.                 case NativeMethods.WindowMessage.MouseMove:
  959.                 case NativeMethods.WindowMessage.MouseWheel:
  960.                 case NativeMethods.WindowMessage.LeftButtonUp:
  961.                 case NativeMethods.WindowMessage.LeftButtonDown:
  962.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  963.                 case NativeMethods.WindowMessage.RightButtonUp:
  964.                 case NativeMethods.WindowMessage.RightButtonDown:
  965.                 case NativeMethods.WindowMessage.RightButtonDoubleClick:
  966.                 case NativeMethods.WindowMessage.MiddleButtonUp:
  967.                 case NativeMethods.WindowMessage.MiddleButtonDown:
  968.                 case NativeMethods.WindowMessage.MiddleButtonDoubleClick:
  969.                 case NativeMethods.WindowMessage.XButtonUp:
  970.                 case NativeMethods.WindowMessage.XButtonDown:
  971.                 case NativeMethods.WindowMessage.XButtonDoubleClick:
  972.                 {
  973.                     // If not accepting mouse input, return false to indicate the message should still 
  974.                     // be handled by the application (usually to move the camera).
  975.                     if (!usingMouseInput)
  976.                         return false;
  977.  
  978.                     // Current mouse position
  979.                     short mouseX = NativeMethods.LoWord((uint)lParam.ToInt32());
  980.                     short mouseY = NativeMethods.HiWord((uint)lParam.ToInt32());
  981.                     System.Drawing.Point mousePoint = new System.Drawing.Point(mouseX, mouseY);
  982.                     // Offset mouse point
  983.                     mousePoint.X -= dialogX;
  984.                     mousePoint.Y -= dialogY;
  985.  
  986.                     // If caption is enabled, offset the Y coordinate by the negative of its height.
  987.                     if (hasCaption)
  988.                         mousePoint.Y -= captionHeight;
  989.  
  990.                     // If a control is in focus, it belongs to this dialog, and it's enabled, then give
  991.                     // it the first chance at handling the message.
  992.                     if (controlFocus != null && 
  993.                         controlFocus.Parent == this && 
  994.                         controlFocus.IsEnabled)
  995.                     {
  996.                         // If the control MsgProc handles it, then we don't.
  997.                         if (controlFocus.HandleMouse(msg, mousePoint, wParam, lParam))
  998.                             return true;
  999.                     }
  1000.  
  1001.                     // Not yet handled, see if the mouse is over any controls
  1002.                     Control control = GetControlAtPoint(mousePoint);
  1003.                     if ((control != null) && (control.IsEnabled))
  1004.                     {
  1005.                         // Let the control handle the mouse if it wants (and return true if it handles it)
  1006.                         if (control.HandleMouse(msg, mousePoint, wParam, lParam))
  1007.                             return true;
  1008.                     }
  1009.                     else
  1010.                     {
  1011.                         // Mouse not over any controls in this dialog, if there was a control
  1012.                         // which had focus it just lost it
  1013.                         if (msg == NativeMethods.WindowMessage.LeftButtonDown &&
  1014.                             controlFocus != null &&
  1015.                             controlFocus.Parent == this)
  1016.                         {
  1017.                             controlFocus.OnFocusOut();
  1018.                             controlFocus = null;
  1019.                         }
  1020.                     }
  1021.  
  1022.                     // Still not handled, hand this off to the dialog. Return false to indicate the
  1023.                     // message should still be handled by the application (usually to move the camera).
  1024.                     switch(msg)
  1025.                     {
  1026.                         case NativeMethods.WindowMessage.MouseMove:
  1027.                             OnMouseMove(mousePoint);
  1028.                             return false;
  1029.                     }
  1030.  
  1031.  
  1032.                 }
  1033.                     break;
  1034.             }
  1035.  
  1036.             // Didn't handle this message
  1037.             return false;
  1038.         }
  1039.  
  1040.         /// <summary>
  1041.         /// Handle mouse moves
  1042.         /// </summary>
  1043.         private void OnMouseMove(System.Drawing.Point pt)
  1044.         {
  1045.             // If the mouse was previously hovering over a control, it's either
  1046.             // still over the control or has left
  1047.             if (controlMouseDown != null)
  1048.             {
  1049.                 // If another dialog owns this control then let that dialog handle it
  1050.                 if (controlMouseDown.Parent != this )
  1051.                     return;
  1052.  
  1053.                 // If the same control is still under the mouse, nothing needs to be done
  1054.                 if (controlMouseDown.ContainsPoint(pt))
  1055.                     return;
  1056.            
  1057.                 // Mouse has moved outside the control, notify the control and continue
  1058.                 controlMouseDown.OnMouseExit();
  1059.                 controlMouseDown = null;
  1060.             }
  1061.  
  1062.             // Figure out which control the mouse is over now
  1063.             Control control = GetControlAtPoint(pt);
  1064.             if (control != null)
  1065.             {
  1066.                 controlMouseDown = control;
  1067.                 controlMouseDown.OnMouseEnter();
  1068.             }
  1069.         }
  1070.         #endregion
  1071.         
  1072.         #region Focus
  1073.         /// <summary>
  1074.         /// Request that this control has focus
  1075.         /// </summary>
  1076.         public static void RequestFocus(Control control)
  1077.         {
  1078.             if (controlFocus == control)
  1079.                 return; // Already does
  1080.  
  1081.             if (!control.CanHaveFocus)
  1082.                 return; // Can't have focus
  1083.  
  1084.             if (controlFocus != null)
  1085.                 controlFocus.OnFocusOut();
  1086.  
  1087.             // Set the control focus now
  1088.             control.OnFocusIn();
  1089.             controlFocus = control;
  1090.         }
  1091.  
  1092.         /// <summary>
  1093.         /// Clears focus of the dialog
  1094.         /// </summary>
  1095.         public static void ClearFocus()
  1096.         {
  1097.             if (controlFocus != null)
  1098.             {
  1099.                 controlFocus.OnFocusOut();
  1100.                 controlFocus = null;
  1101.             }
  1102.         }
  1103.         /// <summary>
  1104.         /// Cycles focus to the next available control
  1105.         /// </summary>
  1106.         private void OnCycleFocus(bool forward)
  1107.         {
  1108.             // This should only be handled by the dialog which owns the focused control, and 
  1109.             // only if a control currently has focus
  1110.             if (controlFocus == null || controlFocus.Parent != this )
  1111.                 return;
  1112.  
  1113.             Control control = controlFocus;
  1114.             // Go through a bunch of controls
  1115.             for (int i = 0; i < 0xffff; i++)
  1116.             {
  1117.                 control = (forward) ? GetNextControl(control) : GetPreviousControl(control);
  1118.  
  1119.                 // If we've gone in a full circle, focus won't change
  1120.                 if (control == controlFocus)
  1121.                     return;
  1122.  
  1123.                 // If the dialog accepts keybord input and the control can have focus then
  1124.                 // move focus
  1125.                 if (control.Parent.IsUsingKeyboardInput && control.CanHaveFocus)
  1126.                 {
  1127.                     controlFocus.OnFocusOut();
  1128.                     controlFocus = control;
  1129.                     controlFocus.OnFocusIn();
  1130.                     return;
  1131.                 }
  1132.             }
  1133.  
  1134.             throw new InvalidOperationException("Multiple dialogs are improperly chained together.");
  1135.         }
  1136.  
  1137.         /// <summary>
  1138.         /// Gets the next control
  1139.         /// </summary>
  1140.         private static Control GetNextControl(Control control)
  1141.         {
  1142.             int index = (int)control.index + 1;
  1143.  
  1144.             Dialog dialog = control.Parent;
  1145.             
  1146.             // Cycle through dialogs in the loop to find the next control. Note
  1147.             // that if only one control exists in all looped dialogs it will
  1148.             // be the returned 'next' control.
  1149.             while (index >= (int)dialog.controlList.Count)
  1150.             {
  1151.                 dialog = dialog.nextDialog;
  1152.                 index = 0;
  1153.             }
  1154.  
  1155.             return dialog.controlList[index] as Control;
  1156.         }
  1157.         /// <summary>
  1158.         /// Gets the previous control
  1159.         /// </summary>
  1160.         private static Control GetPreviousControl(Control control)
  1161.         {
  1162.             int index = (int)control.index - 1;
  1163.  
  1164.             Dialog dialog = control.Parent;
  1165.             
  1166.             // Cycle through dialogs in the loop to find the next control. Note
  1167.             // that if only one control exists in all looped dialogs it will
  1168.             // be the returned 'previous' control.
  1169.             while (index < 0)
  1170.             {
  1171.                 dialog = dialog.prevDialog;
  1172.                 if (dialog == null)
  1173.                     dialog = control.Parent;
  1174.  
  1175.                 index = dialog.controlList.Count - 1;
  1176.             }
  1177.  
  1178.             return dialog.controlList[index] as Control;
  1179.         }
  1180.         /// <summary>
  1181.         /// Sets focus to the default control of a dialog
  1182.         /// </summary>
  1183.         private void FocusDefaultControl()
  1184.         {
  1185.             // Check for a default control in this dialog
  1186.             foreach(Control c in controlList)
  1187.             {
  1188.                 if (c.isDefault)
  1189.                 {
  1190.                     // Remove focus from the current control
  1191.                     ClearFocus();
  1192.  
  1193.                     // Give focus to the default control
  1194.                     controlFocus = c;
  1195.                     controlFocus.OnFocusIn();
  1196.                     return;
  1197.                 }
  1198.             }
  1199.         }
  1200.         #endregion
  1201.  
  1202.         #region Controls Methods/Properties
  1203.         /// <summary>Sets the control enabled property</summary>
  1204.         public void SetControlEnable(int id, bool isenabled)
  1205.         {
  1206.             Control c = GetControl(id);
  1207.             if (c == null)
  1208.                 return; // No control to set
  1209.  
  1210.             c.IsEnabled = isenabled;
  1211.         }
  1212.         /// <summary>Gets the control enabled property</summary>
  1213.         public bool GetControlEnable(int id)
  1214.         {
  1215.             Control c = GetControl(id);
  1216.             if (c == null)
  1217.                 return false; // No control to get
  1218.  
  1219.             return c.IsEnabled;
  1220.         }
  1221.  
  1222.         /// <summary>Returns the control located at a point (if one exists)</summary>
  1223.         public Control GetControlAtPoint(System.Drawing.Point pt)
  1224.         {
  1225.             foreach(Control c in controlList)
  1226.             {
  1227.                 if (c == null)
  1228.                     continue;
  1229.  
  1230.                 if (c.IsEnabled && c.IsVisible && c.ContainsPoint(pt))
  1231.                     return c;
  1232.             }
  1233.  
  1234.             return null;
  1235.         }
  1236.         /// <summary>Returns the control located at this index(if one exists)</summary>
  1237.         public Control GetControl(int id)
  1238.         {
  1239.             foreach(Control c in controlList)
  1240.             {
  1241.                 if (c == null)
  1242.                     continue;
  1243.  
  1244.                 if (c.ID == id)
  1245.                     return c;
  1246.             }
  1247.  
  1248.             return null;
  1249.         }
  1250.         /// <summary>Returns the control located at this index of this type(if one exists)</summary>
  1251.         public Control GetControl(int id, ControlType typeControl)
  1252.         {
  1253.             foreach(Control c in controlList)
  1254.             {
  1255.                 if (c == null)
  1256.                     continue;
  1257.  
  1258.                 if ((c.ID == id) && (c.ControlType == typeControl))
  1259.                     return c;
  1260.             }
  1261.  
  1262.             return null;
  1263.         }
  1264.  
  1265.         /// <summary>Returns the static text control located at this index(if one exists)</summary>
  1266.         public StaticText GetStaticText(int id) { return GetControl(id, ControlType.StaticText) as StaticText; }
  1267.         /// <summary>Returns the button control located at this index(if one exists)</summary>
  1268.         public Button GetButton(int id) { return GetControl(id, ControlType.Button) as Button; }
  1269.         /// <summary>Returns the checkbox control located at this index(if one exists)</summary>
  1270.         public Checkbox GetCheckbox(int id) { return GetControl(id, ControlType.CheckBox) as Checkbox; }
  1271.         /// <summary>Returns the radio button control located at this index(if one exists)</summary>
  1272.         public RadioButton GetRadioButton(int id) { return GetControl(id, ControlType.RadioButton) as RadioButton; }
  1273.         /// <summary>Returns the combo box control located at this index(if one exists)</summary>
  1274.         public ComboBox GetComboBox(int id) { return GetControl(id, ControlType.ComboBox) as ComboBox; }
  1275.         /// <summary>Returns the slider control located at this index(if one exists)</summary>
  1276.         public Slider GetSlider(int id) { return GetControl(id, ControlType.Slider) as Slider; }
  1277.         /// <summary>Returns the listbox control located at this index(if one exists)</summary>
  1278.         public ListBox GetListBox(int id) { return GetControl(id, ControlType.ListBox) as ListBox; }
  1279.         #endregion
  1280.  
  1281.         #region Default Elements
  1282.         /// <summary>
  1283.         /// Sets the default element
  1284.         /// </summary>
  1285.         public void SetDefaultElement(ControlType ctype, uint index, Element e)
  1286.         {
  1287.             // If this element already exists, just update it
  1288.             for (int i = 0; i < defaultElementList.Count; i++)
  1289.             {
  1290.                 ElementHolder holder = (ElementHolder)defaultElementList[i];
  1291.                 if ( (holder.ControlType == ctype) &&
  1292.                     (holder.ElementIndex == index) )
  1293.                 {
  1294.                     // Found it, update it
  1295.                     holder.Element = e.Clone();
  1296.                     defaultElementList[i] = holder;
  1297.                     return;
  1298.                 }
  1299.             }
  1300.  
  1301.             // Couldn't find it, add a new entry
  1302.             ElementHolder newEntry = new ElementHolder();
  1303.             newEntry.ControlType = ctype;
  1304.             newEntry.ElementIndex = index;
  1305.             newEntry.Element = e.Clone();
  1306.  
  1307.             // Add it now
  1308.             defaultElementList.Add(newEntry);
  1309.         }
  1310.         /// <summary>
  1311.         /// Gets the default element
  1312.         /// </summary>
  1313.         public Element GetDefaultElement(ControlType ctype, uint index)
  1314.         {
  1315.             for (int i = 0; i < defaultElementList.Count; i++)
  1316.             {
  1317.                 ElementHolder holder = (ElementHolder)defaultElementList[i];
  1318.                 if ( (holder.ControlType == ctype) &&
  1319.                     (holder.ElementIndex == index) )
  1320.                 {
  1321.                     // Found it, return it
  1322.                     return holder.Element;
  1323.                 }
  1324.             }
  1325.             return null;
  1326.         }
  1327.         #endregion
  1328.  
  1329.         #region Texture/Font Resources
  1330.         /// <summary>
  1331.         /// Shared resource access. Indexed fonts and textures are shared among
  1332.         /// all the controls.
  1333.         /// </summary>
  1334.         public void SetFont(uint index, string faceName, uint height, FontWeight weight)
  1335.         {
  1336.             // Make sure the list is at least big enough to hold this index
  1337.             for (uint i = (uint)fontList.Count; i <= index; i++)
  1338.                 fontList.Add((int)(-1));
  1339.  
  1340.             int fontIndex = DialogResourceManager.GetGlobalInstance().AddFont(faceName, height, weight);
  1341.             fontList[(int)index] = fontIndex;
  1342.         }
  1343.         /// <summary>
  1344.         /// Shared resource access. Indexed fonts and textures are shared among
  1345.         /// all the controls.
  1346.         /// </summary>
  1347.         public FontNode GetFont(uint index)
  1348.         {
  1349.             return DialogResourceManager.GetGlobalInstance().GetFontNode((int)fontList[(int)index]);
  1350.         }
  1351.         /// <summary>
  1352.         /// Shared resource access. Indexed fonts and textures are shared among
  1353.         /// all the controls.
  1354.         /// </summary>
  1355.         public void SetTexture(uint index, string filename)
  1356.         {
  1357.             // Make sure the list is at least big enough to hold this index
  1358.             for (uint i = (uint)textureList.Count; i <= index; i++)
  1359.                 textureList.Add((int)(-1));
  1360.  
  1361.             int textureIndex = DialogResourceManager.GetGlobalInstance().AddTexture(filename);
  1362.             textureList[(int)index] = textureIndex;
  1363.         }
  1364.         /// <summary>
  1365.         /// Shared resource access. Indexed fonts and textures are shared among
  1366.         /// all the controls.
  1367.         /// </summary>
  1368.         public TextureNode GetTexture(uint index)
  1369.         {
  1370.             return DialogResourceManager.GetGlobalInstance().GetTextureNode((int)textureList[(int)index]);
  1371.         }
  1372.         #endregion
  1373.  
  1374.         #region Control Creation
  1375.         /// <summary>
  1376.         /// Initializes a control
  1377.         /// </summary>
  1378.         public void InitializeControl(Control control)
  1379.         {
  1380.             if (control == null)
  1381.                 throw new ArgumentNullException("control", "You cannot pass in a null control to initialize");
  1382.  
  1383.             // Set the index
  1384.             control.index = (uint)controlList.Count;
  1385.  
  1386.             // Look for a default element entires
  1387.             for (int i = 0; i < defaultElementList.Count; i++)
  1388.             {
  1389.                 // Find any elements for this control
  1390.                 ElementHolder holder = (ElementHolder)defaultElementList[i];
  1391.                 if (holder.ControlType == control.ControlType)
  1392.                     control[holder.ElementIndex] = holder.Element;
  1393.             }
  1394.  
  1395.             // Initialize the control
  1396.             control.OnInitialize();
  1397.         }
  1398.         /// <summary>
  1399.         /// Adds a control to the dialog
  1400.         /// </summary>
  1401.         public void AddControl(Control control)
  1402.         {
  1403.             // Initialize the control first
  1404.             InitializeControl(control);
  1405.  
  1406.             // Add this to the control list
  1407.             controlList.Add(control);
  1408.         }
  1409.         /// <summary>Adds a static text control to the dialog</summary>
  1410.         public StaticText AddStatic(int id, string text, int x, int y, int w, int h, bool isDefault)
  1411.         {
  1412.             // First create the static
  1413.             StaticText s = new StaticText(this);
  1414.  
  1415.             // Now call the add control method
  1416.             AddControl(s);
  1417.  
  1418.             // Set the properties of the static now
  1419.             s.ID = id;
  1420.             s.SetText(text);
  1421.             s.SetLocation(x, y);
  1422.             s.SetSize(w,h);
  1423.             s.isDefault = isDefault;
  1424.  
  1425.             return s;
  1426.         }
  1427.         /// <summary>Adds a static text control to the dialog</summary>
  1428.         public StaticText AddStatic(int id, string text, int x, int y, int w, int h){return AddStatic(id, text, x, y, w, h, false); }
  1429.         /// <summary>Adds a button control to the dialog</summary>
  1430.         public Button AddButton(int id, string text, int x, int y, int w, int h, System.Windows.Forms.Keys hotkey, bool isDefault)
  1431.         {
  1432.             // First create the button
  1433.             Button b = new Button(this);
  1434.  
  1435.             // Now call the add control method
  1436.             AddControl(b);
  1437.  
  1438.             // Set the properties of the button now
  1439.             b.ID = id;
  1440.             b.SetText(text);
  1441.             b.SetLocation(x, y);
  1442.             b.SetSize(w,h);
  1443.             b.Hotkey = hotkey;
  1444.             b.isDefault = isDefault;
  1445.  
  1446.             return b;
  1447.         }
  1448.         /// <summary>Adds a button control to the dialog</summary>
  1449.         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); }
  1450.         /// <summary>Adds a checkbox to the dialog</summary>
  1451.         public Checkbox AddCheckBox(int id, string text, int x, int y, int w, int h, bool ischecked, System.Windows.Forms.Keys hotkey, bool isDefault)
  1452.         {
  1453.             // First create the checkbox
  1454.             Checkbox c = new Checkbox(this);
  1455.  
  1456.             // Now call the add control method
  1457.             AddControl(c);
  1458.  
  1459.             // Set the properties of the button now
  1460.             c.ID = id;
  1461.             c.SetText(text);
  1462.             c.SetLocation(x, y);
  1463.             c.SetSize(w,h);
  1464.             c.Hotkey = hotkey;
  1465.             c.isDefault = isDefault;
  1466.             c.IsChecked = ischecked;
  1467.  
  1468.             return c;
  1469.         }
  1470.         /// <summary>Adds a checkbox control to the dialog</summary>
  1471.         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); }
  1472.         /// <summary>Adds a radiobutton to the dialog</summary>
  1473.         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)
  1474.         {
  1475.             // First create the RadioButton
  1476.             RadioButton c = new RadioButton(this);
  1477.  
  1478.             // Now call the add control method
  1479.             AddControl(c);
  1480.  
  1481.             // Set the properties of the button now
  1482.             c.ID = id;
  1483.             c.ButtonGroup = groupId;
  1484.             c.SetText(text);
  1485.             c.SetLocation(x, y);
  1486.             c.SetSize(w,h);
  1487.             c.Hotkey = hotkey;
  1488.             c.isDefault = isDefault;
  1489.             c.IsChecked = ischecked;
  1490.  
  1491.             return c;
  1492.         }
  1493.         /// <summary>Adds a radio button control to the dialog</summary>
  1494.         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); }
  1495.         /// <summary>Adds a combobox control to the dialog</summary>
  1496.         public ComboBox AddComboBox(int id, int x, int y, int w, int h, System.Windows.Forms.Keys hotkey, bool isDefault)
  1497.         {
  1498.             // First create the combo
  1499.             ComboBox c = new ComboBox(this);
  1500.  
  1501.             // Now call the add control method
  1502.             AddControl(c);
  1503.  
  1504.             // Set the properties of the button now
  1505.             c.ID = id;
  1506.             c.SetLocation(x, y);
  1507.             c.SetSize(w,h);
  1508.             c.Hotkey = hotkey;
  1509.             c.isDefault = isDefault;
  1510.  
  1511.             return c;
  1512.         }
  1513.         /// <summary>Adds a combobox control to the dialog</summary>
  1514.         public ComboBox AddComboBox(int id, int x, int y, int w, int h) { return AddComboBox(id, x, y, w, h, 0, false); }
  1515.         /// <summary>Adds a slider control to the dialog</summary>
  1516.         public Slider AddSlider(int id, int x, int y, int w, int h, int min, int max, int initialValue, bool isDefault)
  1517.         {
  1518.             // First create the slider
  1519.             Slider c = new Slider(this);
  1520.  
  1521.             // Now call the add control method
  1522.             AddControl(c);
  1523.  
  1524.             // Set the properties of the button now
  1525.             c.ID = id;
  1526.             c.SetLocation(x, y);
  1527.             c.SetSize(w,h);
  1528.             c.isDefault = isDefault;
  1529.             c.SetRange(min, max);
  1530.             c.Value = initialValue;
  1531.  
  1532.             return c;
  1533.         }
  1534.         /// <summary>Adds a slider control to the dialog</summary>
  1535.         public Slider AddSlider(int id, int x, int y, int w, int h) { return AddSlider(id, x, y, w, h, 0,100,50, false); }
  1536.         /// <summary>Adds a listbox control to the dialog</summary>
  1537.         public ListBox AddListBox(int id, int x, int y, int w, int h, ListBoxStyle style)
  1538.         {
  1539.             // First create the listbox
  1540.             ListBox c = new ListBox(this);
  1541.  
  1542.             // Now call the add control method
  1543.             AddControl(c);
  1544.  
  1545.             // Set the properties of the button now
  1546.             c.ID = id;
  1547.             c.SetLocation(x, y);
  1548.             c.SetSize(w,h);
  1549.             c.Style = style;
  1550.  
  1551.             return c;
  1552.         }
  1553.         /// <summary>Adds a listbox control to the dialog</summary>
  1554.         public ListBox AddListBox(int id, int x, int y, int w, int h) { return AddListBox(id, x, y, w, h, ListBoxStyle.SingleSelection); }
  1555.         /// <summary>Adds an edit box control to the dialog</summary>
  1556.         public EditBox AddEditBox(int id, string text, int x, int y, int w, int h, bool isDefault)
  1557.         {
  1558.             // First create the editbox
  1559.             EditBox c = new EditBox(this);
  1560.  
  1561.             // Now call the add control method
  1562.             AddControl(c);
  1563.  
  1564.             // Set the properties of the static now
  1565.             c.ID = id;
  1566.             c.Text = (text != null) ? text : string.Empty;
  1567.             c.SetLocation(x, y);
  1568.             c.SetSize(w,h);
  1569.             c.isDefault = isDefault;
  1570.  
  1571.             return c;
  1572.         }
  1573.         /// <summary>Adds an edit box control to the dialog</summary>
  1574.         public EditBox AddEditBox(int id, string text, int x, int y, int w, int h){return AddEditBox(id, text, x, y, w, h, false); }
  1575.         #endregion
  1576.  
  1577.         /// <summary>Render the dialog</summary>
  1578.         private void UpdateVertices()
  1579.         {
  1580.             vertices = new Microsoft.DirectX.Direct3D.CustomVertex.TransformedColoredTextured[] {
  1581.                 new CustomVertex.TransformedColoredTextured(dialogX,dialogY,0.5f,1.0f,topLeftColor.ToArgb(),0.0f,0.5f),
  1582.                 new CustomVertex.TransformedColoredTextured(dialogX + width,dialogY,0.5f,1.0f,topRightColor.ToArgb(),1.0f,0.5f),
  1583.                 new CustomVertex.TransformedColoredTextured(dialogX+width,dialogY+height,0.5f,1.0f,bottomRightColor.ToArgb(),1.0f,1.0f),
  1584.                 new CustomVertex.TransformedColoredTextured(dialogX,dialogY+height,0.5f,1.0f,bottomLeftColor.ToArgb(),0.0f,1.0f)
  1585.             };
  1586.         }
  1587.         #region Drawing methods
  1588.         /// <summary>Render the dialog</summary>
  1589.         public void OnRender(float elapsedTime)
  1590.         {
  1591.             // See if the dialog needs to be refreshed
  1592.             if (timeLastRefresh < timeRefresh)
  1593.             {
  1594.                 timeLastRefresh = FrameworkTimer.GetTime();
  1595.                 Refresh();
  1596.             }
  1597.  
  1598.             Device device = DialogResourceManager.GetGlobalInstance().Device;
  1599.  
  1600.             // Set up a state block here and restore it when finished drawing all the controls
  1601.             DialogResourceManager.GetGlobalInstance().StateBlock.Capture();
  1602.  
  1603.             // Set some render/texture states
  1604.             device.RenderState.AlphaBlendEnable = true;
  1605.             device.RenderState.SourceBlend = Blend.SourceAlpha;
  1606.             device.RenderState.DestinationBlend = Blend.InvSourceAlpha;
  1607.             device.RenderState.AlphaTestEnable = false;
  1608.             device.TextureState[0].ColorOperation = TextureOperation.SelectArg2;
  1609.             device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
  1610.             device.TextureState[0].AlphaOperation = TextureOperation.SelectArg1;
  1611.             device.TextureState[0].AlphaArgument1 = TextureArgument.Diffuse;
  1612.             device.RenderState.ZBufferEnable = false;
  1613.             // Clear vertex/pixel shader
  1614.             device.VertexShader = null;
  1615.             device.PixelShader = null;
  1616.  
  1617.             // Render if not minimized
  1618.             if (!isDialogMinimized)
  1619.             {
  1620.                 device.VertexFormat = CustomVertex.TransformedColoredTextured.Format;
  1621.                 device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vertices);
  1622.             }
  1623.  
  1624.             // Reset states
  1625.             device.TextureState[0].ColorOperation = TextureOperation.Modulate;
  1626.             device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
  1627.             device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
  1628.             device.TextureState[0].AlphaOperation = TextureOperation.Modulate;
  1629.             device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
  1630.             device.TextureState[0].AlphaArgument2 = TextureArgument.Diffuse;
  1631.  
  1632.             device.SamplerState[0].MinFilter = TextureFilter.Linear;
  1633.  
  1634.             // Set the texture up, and begin the sprite
  1635.             TextureNode tNode = GetTexture(0);
  1636.             device.SetTexture(0, tNode.Texture);
  1637.             DialogResourceManager.GetGlobalInstance().Sprite.Begin(SpriteFlags.DoNotSaveState);
  1638.  
  1639.             // Render the caption if it's enabled.
  1640.             if (hasCaption)
  1641.             {
  1642.                 // DrawSprite will offset the rect down by
  1643.                 // captionHeight, so adjust the rect higher
  1644.                 // here to negate the effect.
  1645.                 System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0,-captionHeight,width,0);
  1646.                 DrawSprite(captionElement, rect);
  1647.                 rect.Offset(5, 0); // Make a left margin
  1648.                 string output = caption + ((isDialogMinimized) ? " (Minimized)" : null);
  1649.                 DrawText(output, captionElement, rect, true);
  1650.             }
  1651.  
  1652.             // If the dialog is minimized, skip rendering
  1653.             // its controls.
  1654.             if (!isDialogMinimized)
  1655.             {
  1656.                 for(int i = 0; i < controlList.Count; i++)
  1657.                 {
  1658.                     // Focused control is drawn last
  1659.                     if (controlList[i] == controlFocus)
  1660.                         continue;
  1661.  
  1662.                     (controlList[i] as Control).Render(device, elapsedTime);
  1663.                 }
  1664.  
  1665.                 // Render the focus control if necessary
  1666.                 if (controlFocus != null && controlFocus.Parent == this)
  1667.                     controlFocus.Render(device, elapsedTime);
  1668.             }
  1669.  
  1670.             // End the sprite and apply the stateblock
  1671.             DialogResourceManager.GetGlobalInstance().Sprite.End();
  1672.             DialogResourceManager.GetGlobalInstance().StateBlock.Apply();
  1673.         }
  1674.  
  1675.         /// <summary>
  1676.         /// Refresh the dialog
  1677.         /// </summary>
  1678.         private void Refresh()
  1679.         {
  1680.             // Reset the controls
  1681.             if (controlFocus != null)
  1682.                 controlFocus.OnFocusOut();
  1683.  
  1684.             if (controlMouseOver != null)
  1685.                 controlMouseOver.OnMouseExit();
  1686.  
  1687.             controlFocus = null;
  1688.             controlMouseDown = null;
  1689.             controlMouseOver = null;
  1690.  
  1691.             // Refresh any controls
  1692.             foreach(Control c in controlList)
  1693.             {
  1694.                 c.Refresh();
  1695.             }
  1696.  
  1697.             if (usingKeyboardInput)
  1698.                 FocusDefaultControl();
  1699.         }
  1700.  
  1701.         /// <summary>Draw's some text</summary>
  1702.         public void DrawText(string text, Element element, System.Drawing.Rectangle rect, bool shadow)
  1703.         {
  1704.             // No need to draw fully transparant layers
  1705.             if (element.FontColor.Current.Alpha == 0)
  1706.                 return; // Nothing to do
  1707.  
  1708.             System.Drawing.Rectangle screenRect = rect;
  1709.             screenRect.Offset(dialogX, dialogY);
  1710.  
  1711.             // If caption is enabled, offset the Y position by its height.
  1712.             if (hasCaption)
  1713.                 screenRect.Offset(0, captionHeight);
  1714.  
  1715.             // Set the identity transform
  1716.             DialogResourceManager.GetGlobalInstance().Sprite.Transform = Matrix.Identity;
  1717.  
  1718.             // Get the font node here
  1719.             FontNode fNode = GetFont(element.FontIndex);
  1720.             if (shadow)
  1721.             {
  1722.                 // Render the text shadowed
  1723.                 System.Drawing.Rectangle shadowRect = screenRect;
  1724.                 shadowRect.Offset(1, 1);
  1725.                 fNode.Font.DrawText(DialogResourceManager.GetGlobalInstance().Sprite, text,
  1726.                     shadowRect, element.textFormat, unchecked((int)0xff000000));
  1727.             }
  1728.  
  1729.             fNode.Font.DrawText(DialogResourceManager.GetGlobalInstance().Sprite, text,
  1730.                 screenRect, element.textFormat, element.FontColor.Current.ToArgb());
  1731.         }
  1732.         /// <summary>Draw a sprite</summary>
  1733.         public void DrawSprite(Element element, System.Drawing.Rectangle rect)
  1734.         {
  1735.             // No need to draw fully transparant layers
  1736.             if (element.TextureColor.Current.Alpha == 0)
  1737.                 return; // Nothing to do
  1738.  
  1739.             System.Drawing.Rectangle texRect = element.textureRect;
  1740.             System.Drawing.Rectangle screenRect = rect;
  1741.             screenRect.Offset(dialogX, dialogY);
  1742.  
  1743.             // If caption is enabled, offset the Y position by its height.
  1744.             if (hasCaption)
  1745.                 screenRect.Offset(0, captionHeight);
  1746.  
  1747.             // Get the texture
  1748.             TextureNode tNode = GetTexture(element.TextureIndex);
  1749.             float scaleX = (float)screenRect.Width / (float)texRect.Width;
  1750.             float scaleY = (float)screenRect.Height / (float)texRect.Height;
  1751.  
  1752.             // Set the scaling transform
  1753.             DialogResourceManager.GetGlobalInstance().Sprite.Transform = Matrix.Scaling(scaleX, scaleY, 1.0f);
  1754.             
  1755.             // Calculate the position
  1756.             Vector3 pos = new Vector3(screenRect.Left, screenRect.Top, 0.0f);
  1757.             pos.X /= scaleX;
  1758.             pos.Y /= scaleY;
  1759.  
  1760.             // Finally draw the sprite
  1761.             DialogResourceManager.GetGlobalInstance().Sprite.Draw(tNode.Texture, texRect, new Vector3(), pos, element.TextureColor.Current.ToArgb()); 
  1762.         }
  1763.         /// <summary>Draw's some text</summary>
  1764.         public void DrawText(string text, Element element, System.Drawing.Rectangle rect) { this.DrawText(text, element, rect, false); }
  1765.         /// <summary>Draw a rectangle</summary>
  1766.         public void DrawRectangle(System.Drawing.Rectangle rect, ColorValue color)
  1767.         {
  1768.             // Offset the rectangle
  1769.             rect.Offset(dialogX, dialogY);
  1770.  
  1771.             // If caption is enabled, offset the Y position by its height
  1772.             if (hasCaption)
  1773.                 rect.Offset(0, captionHeight);
  1774.  
  1775.             // Get the integer value of the color
  1776.             int realColor = color.ToArgb();
  1777.             // Create some vertices
  1778.             CustomVertex.TransformedColoredTextured[] verts = {
  1779.                 new CustomVertex.TransformedColoredTextured((float)rect.Left - 0.5f, (float)rect.Top -0.5f, 0.5f, 1.0f, realColor, 0, 0),
  1780.                 new CustomVertex.TransformedColoredTextured((float)rect.Right - 0.5f, (float)rect.Top -0.5f, 0.5f, 1.0f, realColor, 0, 0),
  1781.                 new CustomVertex.TransformedColoredTextured((float)rect.Right - 0.5f, (float)rect.Bottom -0.5f, 0.5f, 1.0f, realColor, 0, 0),
  1782.                 new CustomVertex.TransformedColoredTextured((float)rect.Left - 0.5f, (float)rect.Bottom -0.5f, 0.5f, 1.0f, realColor, 0, 0),
  1783.             };
  1784.  
  1785.             // Get the device
  1786.             Device device = SampleFramework.Device;
  1787.  
  1788.             // Since we're doing our own drawing here, we need to flush the sprites
  1789.             DialogResourceManager.GetGlobalInstance().Sprite.Flush();
  1790.             // Preserve the devices current vertex declaration
  1791.             using (VertexDeclaration decl = device.VertexDeclaration)
  1792.             {
  1793.                 // Set the vertex format
  1794.                 device.VertexFormat = CustomVertex.TransformedColoredTextured.Format;
  1795.  
  1796.                 // Set some texture states
  1797.                 device.TextureState[0].ColorOperation = TextureOperation.SelectArg2;
  1798.                 device.TextureState[0].AlphaOperation = TextureOperation.SelectArg2;
  1799.  
  1800.                 // Draw the rectangle
  1801.                 device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, verts);
  1802.  
  1803.                 // Reset some texture states
  1804.                 device.TextureState[0].ColorOperation = TextureOperation.Modulate;
  1805.                 device.TextureState[0].AlphaOperation = TextureOperation.Modulate;
  1806.  
  1807.                 // Restore the vertex declaration
  1808.                 device.VertexDeclaration = decl;
  1809.             }
  1810.         }
  1811.         #endregion
  1812.  
  1813.     }
  1814.  
  1815.     #region Abstract Control class
  1816.     /// <summary>Base class for all controls</summary>
  1817.     public abstract class Control
  1818.     {
  1819.         #region Instance data
  1820.         protected Dialog parentDialog; // Parent container
  1821.         public uint index; // Index within the control list
  1822.         public bool isDefault;
  1823.  
  1824.         // Protected members
  1825.         protected object localUserData; // User specificied data
  1826.         protected bool visible;
  1827.         protected bool isMouseOver;
  1828.         protected bool hasFocus;
  1829.         protected int controlId; // ID Number
  1830.         protected ControlType controlType; // Control type, set in constructor
  1831.         protected System.Windows.Forms.Keys hotKey; // Controls hotkey
  1832.         protected bool enabled; // Enabled/disabled flag
  1833.         protected System.Drawing.Rectangle boundingBox; // Rectangle defining the active region of the control
  1834.  
  1835.         protected int controlX,controlY,width,height; // Size, scale, and positioning members
  1836.  
  1837.         protected ArrayList elementList = new ArrayList(); // All display elements
  1838.         #endregion
  1839.  
  1840.         /// <summary>Initialize the control</summary>
  1841.         public virtual void OnInitialize() {} // Nothing to do here
  1842.         /// <summary>Render the control</summary>
  1843.         public virtual void Render(Device device, float elapsedTime) {} // Nothing to do here
  1844.         /// <summary>Message Handler</summary>
  1845.         public virtual bool MsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam) {return false;} // Nothing to do here
  1846.         /// <summary>Handle the keyboard data</summary>
  1847.         public virtual bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam) {return false;} // Nothing to do here
  1848.         /// <summary>Handle the mouse data</summary>
  1849.         public virtual bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam) {return false;} // Nothing to do here
  1850.  
  1851.         /// <summary>User specified data</summary>
  1852.         public object UserData { get { return localUserData; } set { localUserData = value; } }
  1853.         /// <summary>The parent dialog of this control</summary>
  1854.         public Dialog Parent { get { return parentDialog; } }
  1855.         /// <summary>Can the control have focus</summary>
  1856.         public virtual bool CanHaveFocus { get { return false; } }
  1857.         /// <summary>Called when control gets focus</summary>
  1858.         public virtual void OnFocusIn() { hasFocus = true;}
  1859.         /// <summary>Called when control loses focus</summary>
  1860.         public virtual void OnFocusOut() { hasFocus = false;}
  1861.         /// <summary>Called when mouse goes over the control</summary>
  1862.         public virtual void OnMouseEnter() { isMouseOver = true;}
  1863.         /// <summary>Called when mouse leaves the control</summary>
  1864.         public virtual void OnMouseExit() { isMouseOver = false;}
  1865.         /// <summary>Called when the control's hotkey is hit</summary>
  1866.         public virtual void OnHotKey() {} // Nothing to do here
  1867.         /// <summary>Does the control contain this point</summary>
  1868.         public virtual bool ContainsPoint(System.Drawing.Point pt) { return boundingBox.Contains(pt); }
  1869.         /// <summary>Is the control enabled</summary>
  1870.         public virtual bool IsEnabled { get { return enabled; } set { enabled = value; } }
  1871.         /// <summary>Is the control visible</summary>
  1872.         public virtual bool IsVisible { get { return visible; } set { visible = value; } }
  1873.         /// <summary>Type of the control</summary>
  1874.         public virtual ControlType ControlType { get { return controlType; } }
  1875.         /// <summary>Unique ID of the control</summary>
  1876.         public virtual int ID { get { return controlId; } set { controlId = value; } }
  1877.         /// <summary>Called to set control's location</summary>
  1878.         public virtual void SetLocation(int x, int y) { controlX = x; controlY = y; UpdateRectangles(); }
  1879.         /// <summary>Called to set control's size</summary>
  1880.         public virtual void SetSize(int w, int h) { width = w; height = h; UpdateRectangles(); }
  1881.         /// <summary>The controls hotkey</summary>
  1882.         public virtual System.Windows.Forms.Keys Hotkey { get { return hotKey; } set { hotKey = value; } }
  1883.  
  1884.         /// <summary>
  1885.         /// Index for the elements this control has access to
  1886.         /// </summary>
  1887.         public Element this[uint index]
  1888.         {
  1889.             get { return elementList[(int)index] as Element; }
  1890.             set 
  1891.             { 
  1892.                 if (value == null)
  1893.                     throw new ArgumentNullException("ControlIndexer", "You cannot set a null element.");
  1894.                 
  1895.                 // Is the collection big enough?
  1896.                 for(uint i = (uint)elementList.Count; i <= index; i++)
  1897.                 {
  1898.                     // Add a new one
  1899.                     elementList.Add(new Element());
  1900.                 }
  1901.                 // Update the data (with a clone)
  1902.                 elementList[(int)index] = value.Clone();
  1903.             }
  1904.         }
  1905.         /// <summary>
  1906.         /// Create a new instance of a control
  1907.         /// </summary>
  1908.         protected Control(Dialog parent)
  1909.         {
  1910.             controlType = ControlType.Button;
  1911.             parentDialog = parent;
  1912.             controlId = 0;
  1913.             index = 0;
  1914.  
  1915.             enabled = true;
  1916.             visible = true;
  1917.             isMouseOver = false;
  1918.             hasFocus = false;
  1919.             isDefault = false;
  1920.  
  1921.             controlX = 0; controlY = 0; width = 0; height = 0;
  1922.         }
  1923.  
  1924.         /// <summary>
  1925.         /// Refreshes the control
  1926.         /// </summary>
  1927.         public virtual void Refresh()
  1928.         {
  1929.             isMouseOver = false;
  1930.             hasFocus = false;
  1931.             for(int i = 0; i < elementList.Count; i++)
  1932.             {
  1933.                 (elementList[i] as Element).Refresh();
  1934.             }
  1935.         }
  1936.  
  1937.         /// <summary>
  1938.         /// Updates the rectangles
  1939.         /// </summary>
  1940.         protected virtual void UpdateRectangles()
  1941.         {
  1942.             boundingBox = new System.Drawing.Rectangle(controlX, controlY, width, height);
  1943.         }
  1944.     }
  1945.     #endregion
  1946.  
  1947.     #region StaticText control
  1948.     /// <summary>
  1949.     /// StaticText text control
  1950.     /// </summary>
  1951.     public class StaticText : Control
  1952.     {
  1953.         public const int TextElement = 0;
  1954.         protected string textData; // Window text
  1955.  
  1956.         /// <summary>
  1957.         /// Create a new instance of a static text control
  1958.         /// </summary>
  1959.         public StaticText(Dialog parent) : base(parent)
  1960.         {
  1961.             controlType = ControlType.StaticText;
  1962.             parentDialog = parent;
  1963.             textData = string.Empty;
  1964.             elementList.Clear();
  1965.         }
  1966.  
  1967.         /// <summary>
  1968.         /// Render this control
  1969.         /// </summary>
  1970.         public override void Render(Device device, float elapsedTime)
  1971.         {
  1972.             if (!IsVisible)
  1973.                 return; // Nothing to do here
  1974.  
  1975.             ControlState state = ControlState.Normal;
  1976.             if (!IsEnabled)
  1977.                 state = ControlState.Disabled;
  1978.  
  1979.             // Blend the element colors
  1980.             Element e = elementList[TextElement] as Element;
  1981.             e.FontColor.Blend(state, elapsedTime);
  1982.  
  1983.             // Render with a shadow
  1984.             parentDialog.DrawText(textData, e, boundingBox, true);
  1985.         }
  1986.  
  1987.         /// <summary>
  1988.         /// Return a copy of the string
  1989.         /// </summary>
  1990.         public string GetTextCopy()
  1991.         {
  1992.             return textData.Clone() as string;
  1993.         }
  1994.  
  1995.         /// <summary>
  1996.         /// Sets the updated text for this control
  1997.         /// </summary>
  1998.         public void SetText(string newText)
  1999.         {
  2000.             textData = newText;
  2001.         }
  2002.  
  2003.     }
  2004.     #endregion
  2005.  
  2006.     #region Button control
  2007.  
  2008.     /// <summary>
  2009.     /// Button control
  2010.     /// </summary>
  2011.     public class Button : StaticText
  2012.     {
  2013.         public const int ButtonLayer = 0;
  2014.         public const int FillLayer = 1;
  2015.         protected bool isPressed;
  2016.         #region Event code
  2017.         public event EventHandler Click;
  2018.         /// <summary>Create new button instance</summary>
  2019.         protected void RaiseClickEvent(Button sender, bool wasTriggeredByUser)
  2020.         {
  2021.             // Discard events triggered programatically if these types of events haven't been
  2022.             // enabled
  2023.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  2024.                 return;
  2025.  
  2026.             if (Click != null)
  2027.                 Click(sender, EventArgs.Empty);
  2028.         }
  2029.         #endregion
  2030.  
  2031.         /// <summary>Create new button instance</summary>
  2032.         public Button(Dialog parent) : base(parent)
  2033.         {
  2034.             controlType = ControlType.Button;
  2035.             parentDialog = parent;
  2036.             isPressed = false;
  2037.             hotKey = 0;
  2038.         }
  2039.  
  2040.         /// <summary>Can the button have focus</summary>
  2041.         public override bool CanHaveFocus { get { return IsVisible && IsEnabled; } }
  2042.         /// <summary>The hotkey for this button was pressed</summary>
  2043.         public override void OnHotKey()
  2044.         {
  2045.             RaiseClickEvent(this, true);
  2046.         }
  2047.  
  2048.         /// <summary>
  2049.         /// Will handle the keyboard strokes
  2050.         /// </summary>
  2051.         public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  2052.         {
  2053.             if (!IsEnabled || !IsVisible)
  2054.                 return false;
  2055.  
  2056.             switch(msg)
  2057.             {
  2058.                 case NativeMethods.WindowMessage.KeyDown:
  2059.                     if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
  2060.                     {
  2061.                         isPressed = true;
  2062.                         return true;
  2063.                     }
  2064.                     break;
  2065.                 case NativeMethods.WindowMessage.KeyUp:
  2066.                     if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
  2067.                     {
  2068.                         isPressed = false;
  2069.                         RaiseClickEvent(this, true);
  2070.  
  2071.                         return true;
  2072.                     }
  2073.                     break;
  2074.             }
  2075.             return false;
  2076.         }
  2077.  
  2078.         /// <summary>
  2079.         /// Handle mouse messages from the buttons
  2080.         /// </summary>
  2081.         public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
  2082.         {
  2083.             if (!IsEnabled || !IsVisible)
  2084.                 return false;
  2085.  
  2086.             switch(msg)
  2087.             {
  2088.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  2089.                 case NativeMethods.WindowMessage.LeftButtonDown:
  2090.                 {
  2091.                     if (ContainsPoint(pt))
  2092.                     {
  2093.                         // Pressed while inside the control
  2094.                         isPressed = true;
  2095.                         NativeMethods.SetCapture(Parent.SampleFramework.Window);
  2096.                         if (!hasFocus)
  2097.                             Dialog.RequestFocus(this);
  2098.  
  2099.                         return true;
  2100.                     }
  2101.                 }
  2102.                     break;
  2103.                 case NativeMethods.WindowMessage.LeftButtonUp:
  2104.                 {
  2105.                     if (isPressed)
  2106.                     {
  2107.                         isPressed = false;
  2108.                         NativeMethods.ReleaseCapture();
  2109.                         if (!parentDialog.IsUsingKeyboardInput)
  2110.                             Dialog.ClearFocus();
  2111.  
  2112.                         // Button click
  2113.                         if (ContainsPoint(pt))
  2114.                             RaiseClickEvent(this, true);
  2115.                     }
  2116.                 }
  2117.                     break;
  2118.             }
  2119.  
  2120.             return false;
  2121.         }
  2122.  
  2123.         /// <summary>Render the button</summary>
  2124.         public override void Render(Device device, float elapsedTime)
  2125.         {
  2126.             int offsetX = 0;
  2127.             int offsetY = 0;
  2128.  
  2129.             ControlState state = ControlState.Normal;
  2130.             if (IsVisible == false)
  2131.             {
  2132.                 state = ControlState.Hidden;
  2133.             }
  2134.             else if (IsEnabled == false)
  2135.             {
  2136.                 state = ControlState.Disabled;
  2137.             }
  2138.             else if (isPressed)
  2139.             {
  2140.                 state = ControlState.Pressed;
  2141.                 offsetX = 1;
  2142.                 offsetY = 2;
  2143.             }
  2144.             else if (isMouseOver)
  2145.             {
  2146.                 state = ControlState.MouseOver;
  2147.                 offsetX = -1;
  2148.                 offsetY = -2;
  2149.             }
  2150.             else if (hasFocus)
  2151.             {
  2152.                 state = ControlState.Focus;
  2153.             }
  2154.  
  2155.             // Background fill layer
  2156.             Element e = elementList[Button.ButtonLayer] as Element;
  2157.             float blendRate = (state == ControlState.Pressed) ? 0.0f : 0.8f;
  2158.             
  2159.             System.Drawing.Rectangle buttonRect = boundingBox;
  2160.             buttonRect.Offset(offsetX, offsetY);
  2161.             
  2162.             // Blend current color
  2163.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  2164.             e.FontColor.Blend(state, elapsedTime, blendRate);
  2165.  
  2166.             // Draw sprite/text of button
  2167.             parentDialog.DrawSprite(e, buttonRect);
  2168.             parentDialog.DrawText(textData, e, buttonRect);
  2169.  
  2170.             // Main button
  2171.             e = elementList[Button.FillLayer] as Element;
  2172.             
  2173.             // Blend current color
  2174.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  2175.             e.FontColor.Blend(state, elapsedTime, blendRate);
  2176.  
  2177.             parentDialog.DrawSprite(e, buttonRect);
  2178.             parentDialog.DrawText(textData, e, buttonRect);
  2179.         }
  2180.  
  2181.     }
  2182.     #endregion
  2183.  
  2184.     #region Checkbox Control
  2185.     /// <summary>
  2186.     /// Checkbox control
  2187.     /// </summary>
  2188.     public class Checkbox : Button
  2189.     {
  2190.         public const int BoxLayer = 0;
  2191.         public const int CheckLayer = 1;
  2192.         #region Event code
  2193.         public event EventHandler Changed;
  2194.         /// <summary>Create new button instance</summary>
  2195.         protected void RaiseChangedEvent(Checkbox sender, bool wasTriggeredByUser)
  2196.         {
  2197.             // Discard events triggered programatically if these types of events haven't been
  2198.             // enabled
  2199.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  2200.                 return;
  2201.  
  2202.             // Fire both the changed and clicked event
  2203.             base.RaiseClickEvent(sender, wasTriggeredByUser);
  2204.             if (Changed != null)
  2205.                 Changed(sender, EventArgs.Empty);
  2206.         }
  2207.         #endregion
  2208.         protected System.Drawing.Rectangle buttonRect;
  2209.         protected System.Drawing.Rectangle textRect;
  2210.         protected bool isBoxChecked;
  2211.  
  2212.         /// <summary>
  2213.         /// Create new checkbox instance
  2214.         /// </summary>
  2215.         public Checkbox(Dialog parent) : base(parent)
  2216.         {
  2217.             controlType = ControlType.CheckBox;
  2218.             isBoxChecked = false;
  2219.             parentDialog = parent;
  2220.         }
  2221.  
  2222.         /// <summary>
  2223.         /// Checked property
  2224.         /// </summary>
  2225.         public virtual bool IsChecked
  2226.         {
  2227.             get { return isBoxChecked; }
  2228.             set { SetCheckedInternal(value, false); }
  2229.         }
  2230.         /// <summary>
  2231.         /// Sets the checked state and fires the event if necessary
  2232.         /// </summary>
  2233.         protected virtual void SetCheckedInternal(bool ischecked, bool fromInput)
  2234.         {
  2235.             isBoxChecked = ischecked;
  2236.             RaiseChangedEvent(this, fromInput);
  2237.         }
  2238.  
  2239.         /// <summary>
  2240.         /// Override hotkey to fire event
  2241.         /// </summary>
  2242.         public override void OnHotKey()
  2243.         {
  2244.             SetCheckedInternal(!isBoxChecked, true);
  2245.         }
  2246.  
  2247.         /// <summary>
  2248.         /// Does the control contain the point?
  2249.         /// </summary>
  2250.         public override bool ContainsPoint(System.Drawing.Point pt)
  2251.         {
  2252.             return (boundingBox.Contains(pt) || buttonRect.Contains(pt));
  2253.         }
  2254.         /// <summary>
  2255.         /// Update the rectangles
  2256.         /// </summary>
  2257.         protected override void UpdateRectangles()
  2258.         {
  2259.             // Update base first
  2260.             base.UpdateRectangles();
  2261.  
  2262.             // Update the two rects
  2263.             buttonRect = boundingBox;
  2264.             buttonRect = new System.Drawing.Rectangle(boundingBox.Location,
  2265.                 new System.Drawing.Size(boundingBox.Height, boundingBox.Height));
  2266.  
  2267.             textRect = boundingBox;
  2268.             textRect.Offset((int) (1.25f * buttonRect.Width), 0);
  2269.         }
  2270.  
  2271.         /// <summary>
  2272.         /// Render the checkbox control
  2273.         /// </summary>
  2274.         public override void Render(Device device, float elapsedTime)
  2275.         {
  2276.             ControlState state = ControlState.Normal;
  2277.             if (IsVisible == false)
  2278.                 state = ControlState.Hidden;
  2279.             else if (IsEnabled == false)
  2280.                 state = ControlState.Disabled;
  2281.             else if (isPressed)
  2282.                 state = ControlState.Pressed;
  2283.             else if (isMouseOver)
  2284.                 state = ControlState.MouseOver;
  2285.             else if (hasFocus)
  2286.                 state = ControlState.Focus;
  2287.  
  2288.             Element e = elementList[Checkbox.BoxLayer] as Element;
  2289.             float blendRate = (state == ControlState.Pressed) ? 0.0f : 0.8f;
  2290.             
  2291.             // Blend current color
  2292.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  2293.             e.FontColor.Blend(state, elapsedTime, blendRate);
  2294.  
  2295.             // Draw sprite/text of checkbox
  2296.             parentDialog.DrawSprite(e, buttonRect);
  2297.             parentDialog.DrawText(textData, e, textRect);
  2298.  
  2299.             if (!isBoxChecked)
  2300.                 state = ControlState.Hidden;
  2301.  
  2302.             e = elementList[Checkbox.CheckLayer] as Element;
  2303.             // Blend current color
  2304.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  2305.  
  2306.             // Draw sprite of checkbox
  2307.             parentDialog.DrawSprite(e, buttonRect);
  2308.         }
  2309.  
  2310.         /// <summary>
  2311.         /// Handle the keyboard for the checkbox
  2312.         /// </summary>
  2313.         public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  2314.         {
  2315.             if (!IsEnabled || !IsVisible)
  2316.                 return false;
  2317.  
  2318.             switch(msg)
  2319.             {
  2320.                 case NativeMethods.WindowMessage.KeyDown:
  2321.                     if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
  2322.                     {
  2323.                         isPressed = true;
  2324.                         return true;
  2325.                     }
  2326.                     break;
  2327.                 case NativeMethods.WindowMessage.KeyUp:
  2328.                     if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
  2329.                     {
  2330.                         if (isPressed)
  2331.                         {
  2332.                             isPressed = false;
  2333.                             SetCheckedInternal(!isBoxChecked, true);
  2334.                         }
  2335.                         return true;
  2336.                     }
  2337.                     break;
  2338.             }
  2339.             return false;
  2340.         }
  2341.  
  2342.         /// <summary>
  2343.         /// Handle mouse messages from the checkbox
  2344.         /// </summary>
  2345.         public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
  2346.         {
  2347.             if (!IsEnabled || !IsVisible)
  2348.                 return false;
  2349.  
  2350.             switch(msg)
  2351.             {
  2352.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  2353.                 case NativeMethods.WindowMessage.LeftButtonDown:
  2354.                 {
  2355.                     if (ContainsPoint(pt))
  2356.                     {
  2357.                         // Pressed while inside the control
  2358.                         isPressed = true;
  2359.                         NativeMethods.SetCapture(Parent.SampleFramework.Window);
  2360.                         if ( (!hasFocus) && (parentDialog.IsUsingKeyboardInput) )
  2361.                             Dialog.RequestFocus(this);
  2362.  
  2363.                         return true;
  2364.                     }
  2365.                 }
  2366.                     break;
  2367.                 case NativeMethods.WindowMessage.LeftButtonUp:
  2368.                 {
  2369.                     if (isPressed)
  2370.                     {
  2371.                         isPressed = false;
  2372.                         NativeMethods.ReleaseCapture();
  2373.  
  2374.                         // Button click
  2375.                         if (ContainsPoint(pt))
  2376.                         {
  2377.                             SetCheckedInternal(!isBoxChecked, true);
  2378.                         }
  2379.                         
  2380.                         return true;
  2381.                     }
  2382.                 }
  2383.                     break;
  2384.             }
  2385.  
  2386.             return false;
  2387.         }
  2388.     }
  2389.     #endregion
  2390.  
  2391.     #region RadioButton Control
  2392.     /// <summary>
  2393.     /// Radio button control
  2394.     /// </summary>
  2395.     public class RadioButton : Checkbox
  2396.     {
  2397.         protected uint buttonGroupIndex;
  2398.         /// <summary>
  2399.         /// Create new radio button instance
  2400.         /// </summary>
  2401.         public RadioButton(Dialog parent) : base(parent)
  2402.         {
  2403.             controlType = ControlType.RadioButton;
  2404.             parentDialog = parent;
  2405.         }
  2406.  
  2407.         /// <summary>
  2408.         /// Button Group property
  2409.         /// </summary>
  2410.         public uint ButtonGroup
  2411.         {
  2412.             get { return buttonGroupIndex; }
  2413.             set { buttonGroupIndex = value; }
  2414.         }
  2415.  
  2416.         /// <summary>
  2417.         /// Sets the check state and potentially clears the group
  2418.         /// </summary>
  2419.         public void SetChecked(bool ischecked, bool clear)
  2420.         {
  2421.             SetCheckedInternal(ischecked, clear, false); 
  2422.         }
  2423.  
  2424.         /// <summary>
  2425.         /// Sets the checked state and fires the event if necessary
  2426.         /// </summary>
  2427.         protected virtual void SetCheckedInternal(bool ischecked, bool clearGroup, bool fromInput)
  2428.         {
  2429.             isBoxChecked = ischecked;
  2430.             RaiseChangedEvent(this, fromInput);
  2431.         }
  2432.  
  2433.         /// <summary>
  2434.         /// Override hotkey to fire event
  2435.         /// </summary>
  2436.         public override void OnHotKey()
  2437.         {
  2438.             SetCheckedInternal(true, true);
  2439.         }
  2440.  
  2441.         /// <summary>
  2442.         /// Handle the keyboard for the checkbox
  2443.         /// </summary>
  2444.         public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  2445.         {
  2446.             if (!IsEnabled || !IsVisible)
  2447.                 return false;
  2448.  
  2449.             switch(msg)
  2450.             {
  2451.                 case NativeMethods.WindowMessage.KeyDown:
  2452.                     if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
  2453.                     {
  2454.                         isPressed = true;
  2455.                         return true;
  2456.                     }
  2457.                     break;
  2458.                 case NativeMethods.WindowMessage.KeyUp:
  2459.                     if ((System.Windows.Forms.Keys)wParam.ToInt32() == System.Windows.Forms.Keys.Space)
  2460.                     {
  2461.                         if (isPressed)
  2462.                         {
  2463.                             isPressed = false;
  2464.                             parentDialog.ClearRadioButtonGroup(buttonGroupIndex);
  2465.                             isBoxChecked = !isBoxChecked;
  2466.  
  2467.                             RaiseChangedEvent(this, true);
  2468.                         }
  2469.                         return true;
  2470.                     }
  2471.                     break;
  2472.             }
  2473.             return false;
  2474.         }
  2475.  
  2476.         /// <summary>
  2477.         /// Handle mouse messages from the radio button
  2478.         /// </summary>
  2479.         public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
  2480.         {
  2481.             if (!IsEnabled || !IsVisible)
  2482.                 return false;
  2483.  
  2484.             switch(msg)
  2485.             {
  2486.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  2487.                 case NativeMethods.WindowMessage.LeftButtonDown:
  2488.                 {
  2489.                     if (ContainsPoint(pt))
  2490.                     {
  2491.                         // Pressed while inside the control
  2492.                         isPressed = true;
  2493.                         NativeMethods.SetCapture(Parent.SampleFramework.Window);
  2494.                         if ( (!hasFocus) && (parentDialog.IsUsingKeyboardInput) )
  2495.                             Dialog.RequestFocus(this);
  2496.  
  2497.                         return true;
  2498.                     }
  2499.                 }
  2500.                     break;
  2501.                 case NativeMethods.WindowMessage.LeftButtonUp:
  2502.                 {
  2503.                     if (isPressed)
  2504.                     {
  2505.                         isPressed = false;
  2506.                         NativeMethods.ReleaseCapture();
  2507.  
  2508.                         // Button click
  2509.                         if (ContainsPoint(pt))
  2510.                         {
  2511.                             parentDialog.ClearRadioButtonGroup(buttonGroupIndex);
  2512.                             isBoxChecked = !isBoxChecked;
  2513.  
  2514.                             RaiseChangedEvent(this, true);
  2515.                         }
  2516.                         
  2517.                         return true;
  2518.                     }
  2519.                 }
  2520.                     break;
  2521.             }
  2522.  
  2523.             return false;
  2524.         }
  2525.     }
  2526.     #endregion
  2527.  
  2528.     #region Scrollbar control
  2529.     /// <summary>
  2530.     /// A scroll bar control
  2531.     /// </summary>
  2532.     public class ScrollBar : Control
  2533.     {
  2534.         public const int TrackLayer = 0;
  2535.         public const int UpButtonLayer = 1;
  2536.         public const int DownButtonLayer = 2;
  2537.         public const int ThumbLayer = 3;
  2538.         protected const int MinimumThumbSize = 8;
  2539.         #region Instance Data
  2540.         protected bool showingThumb;
  2541.         protected System.Drawing.Rectangle upButtonRect;
  2542.         protected System.Drawing.Rectangle downButtonRect;
  2543.         protected System.Drawing.Rectangle trackRect;
  2544.         protected System.Drawing.Rectangle thumbRect;
  2545.         protected int position; // Position of the first displayed item
  2546.         protected int pageSize; // How many items are displayable in one page
  2547.         protected int start; // First item
  2548.         protected int end; // The index after the last item
  2549.         private int thumbOffsetY;
  2550.         private bool isDragging;
  2551.         #endregion
  2552.  
  2553.         /// <summary>
  2554.         /// Creates a new instance of the scroll bar class
  2555.         /// </summary>
  2556.         public ScrollBar(Dialog parent) : base(parent)
  2557.         {
  2558.             // Store parent and control type
  2559.             controlType = ControlType.Scrollbar;
  2560.             parentDialog = parent;
  2561.  
  2562.             // Set default properties
  2563.             showingThumb = true;
  2564.             upButtonRect = System.Drawing.Rectangle.Empty;
  2565.             downButtonRect = System.Drawing.Rectangle.Empty;
  2566.             trackRect = System.Drawing.Rectangle.Empty;
  2567.             thumbRect = System.Drawing.Rectangle.Empty;
  2568.  
  2569.             position = 0;
  2570.             pageSize = 1;
  2571.             start = 0;
  2572.             end = 1;
  2573.         }
  2574.  
  2575.         /// <summary>
  2576.         /// Update all of the rectangles
  2577.         /// </summary>
  2578.         protected override void UpdateRectangles()
  2579.         {
  2580.             // Get the bounding box first
  2581.             base.UpdateRectangles();
  2582.  
  2583.             // Make sure buttons are square
  2584.             upButtonRect = new System.Drawing.Rectangle(boundingBox.Location,
  2585.                 new System.Drawing.Size(boundingBox.Width, boundingBox.Width));
  2586.  
  2587.             downButtonRect = new System.Drawing.Rectangle(boundingBox.Left, boundingBox.Bottom - boundingBox.Width,
  2588.                 boundingBox.Width, boundingBox.Width);
  2589.  
  2590.             trackRect = new System.Drawing.Rectangle(upButtonRect.Left, upButtonRect.Bottom, 
  2591.                 upButtonRect.Width, downButtonRect.Top - upButtonRect.Bottom);
  2592.  
  2593.             thumbRect = upButtonRect;
  2594.  
  2595.             UpdateThumbRectangle();
  2596.         }
  2597.  
  2598.         /// <summary>
  2599.         /// Position of the track
  2600.         /// </summary>
  2601.         public int TrackPosition
  2602.         {
  2603.             get { return position; }
  2604.             set { position = value; Cap(); UpdateThumbRectangle(); }
  2605.         }
  2606.         /// <summary>
  2607.         /// Size of a 'page'
  2608.         /// </summary>
  2609.         public int PageSize
  2610.         {
  2611.             get { return pageSize; }
  2612.             set { pageSize = value; Cap(); UpdateThumbRectangle(); }
  2613.         }
  2614.  
  2615.         /// <summary>Clips position at boundaries</summary>
  2616.         protected void Cap()
  2617.         {
  2618.             if (position < start || end - start <= pageSize)
  2619.             {
  2620.                 position = start;
  2621.             }
  2622.             else if (position + pageSize > end)
  2623.                 position = end - pageSize;
  2624.         }
  2625.  
  2626.         /// <summary>Compute the dimension of the scroll thumb</summary>
  2627.         protected void UpdateThumbRectangle()
  2628.         {
  2629.             if (end - start > pageSize)
  2630.             {
  2631.                 int thumbHeight = Math.Max(trackRect.Height * pageSize / (end-start), MinimumThumbSize);
  2632.                 int maxPosition = end - start - pageSize;
  2633.                 thumbRect.Location = new System.Drawing.Point(thumbRect.Left,
  2634.                     trackRect.Top + (position - start) * (trackRect.Height - thumbHeight) / maxPosition);
  2635.                 thumbRect.Size = new System.Drawing.Size(thumbRect.Width, thumbHeight);
  2636.                 showingThumb = true;
  2637.             }
  2638.             else
  2639.             {
  2640.                 // No content to scroll
  2641.                 thumbRect.Height = 0;
  2642.                 showingThumb = false;
  2643.             }
  2644.         }
  2645.  
  2646.         /// <summary>Scrolls by delta items.  A positive value scrolls down, while a negative scrolls down</summary>
  2647.         public void Scroll(int delta)
  2648.         {
  2649.             // Perform scroll
  2650.             position += delta;
  2651.             // Cap position
  2652.             Cap();
  2653.             // Update thumb rectangle
  2654.             UpdateThumbRectangle();
  2655.         }
  2656.  
  2657.         /// <summary>Shows an item</summary>
  2658.         public void ShowItem(int index)
  2659.         {
  2660.             // Cap the index
  2661.             if (index < 0)
  2662.                 index = 0;
  2663.  
  2664.             if (index >= end)
  2665.                 index = end - 1;
  2666.  
  2667.             // Adjust the position to show this item
  2668.             if (position > index)
  2669.                 position = index;
  2670.             else if (position + pageSize <= index)
  2671.                 position = index - pageSize + 1;
  2672.  
  2673.             // Update thumbs again
  2674.             UpdateThumbRectangle();
  2675.         }
  2676.  
  2677.         /// <summary>Sets the track range</summary>
  2678.         public void SetTrackRange(int startRange, int endRange)
  2679.         {
  2680.             start = startRange; end = endRange;
  2681.             Cap();
  2682.             UpdateThumbRectangle();
  2683.         }
  2684.  
  2685.         /// <summary>Render the scroll bar control</summary>
  2686.         public override void Render(Device device, float elapsedTime)
  2687.         {
  2688.             ControlState state = ControlState.Normal;
  2689.             if (IsVisible == false)
  2690.                 state = ControlState.Hidden;
  2691.             else if ( (IsEnabled == false) || (showingThumb == false) )
  2692.                 state = ControlState.Disabled;
  2693.             else if (isMouseOver)
  2694.                 state = ControlState.MouseOver;
  2695.             else if (hasFocus)
  2696.                 state = ControlState.Focus;
  2697.  
  2698.             float blendRate = (state == ControlState.Pressed) ? 0.0f : 0.8f;
  2699.  
  2700.             // Background track layer
  2701.             Element e = elementList[ScrollBar.TrackLayer] as Element;
  2702.             
  2703.             // Blend current color
  2704.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  2705.             parentDialog.DrawSprite(e, trackRect);
  2706.  
  2707.             // Up arrow
  2708.             e = elementList[ScrollBar.UpButtonLayer] as Element;
  2709.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  2710.             parentDialog.DrawSprite(e, upButtonRect);
  2711.  
  2712.             // Down arrow
  2713.             e = elementList[ScrollBar.DownButtonLayer] as Element;
  2714.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  2715.             parentDialog.DrawSprite(e, downButtonRect);
  2716.  
  2717.             // Thumb button
  2718.             e = elementList[ScrollBar.ThumbLayer] as Element;
  2719.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  2720.             parentDialog.DrawSprite(e, thumbRect);
  2721.         }
  2722.  
  2723.         /// <summary>Stores data for a combo box item</summary>
  2724.         public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
  2725.         {
  2726.             if (!IsEnabled || !IsVisible)
  2727.                 return false;
  2728.  
  2729.             switch(msg)
  2730.             {
  2731.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  2732.                 case NativeMethods.WindowMessage.LeftButtonDown:
  2733.                 {
  2734.                     NativeMethods.SetCapture(Parent.SampleFramework.Window);
  2735.  
  2736.                     // Check for on up button
  2737.                     if (upButtonRect.Contains(pt))
  2738.                     {
  2739.                         if (position > start)
  2740.                             --position;
  2741.                         UpdateThumbRectangle();
  2742.                         return true;
  2743.                     }
  2744.  
  2745.                     // Check for on down button
  2746.                     if (downButtonRect.Contains(pt))
  2747.                     {
  2748.                         if (position + pageSize < end)
  2749.                             ++position;
  2750.                         UpdateThumbRectangle();
  2751.                         return true;
  2752.                     }
  2753.  
  2754.                     // Check for click on thumb
  2755.                     if (thumbRect.Contains(pt))
  2756.                     {
  2757.                         isDragging = true;
  2758.                         thumbOffsetY = pt.Y - thumbRect.Top;
  2759.                         return true;
  2760.                     }
  2761.  
  2762.                     // check for click on track
  2763.                     if (thumbRect.Left <= pt.X &&
  2764.                         thumbRect.Right > pt.X)
  2765.                     {
  2766.                         if (thumbRect.Top > pt.Y &&
  2767.                             trackRect.Top <= pt.Y)
  2768.                         {
  2769.                             Scroll(-(pageSize-1));
  2770.                             return true;
  2771.                         }
  2772.                         else if (thumbRect.Bottom <= pt.Y &&
  2773.                             trackRect.Bottom > pt.Y)
  2774.                         {
  2775.                             Scroll(pageSize-1);
  2776.                             return true;
  2777.                         }
  2778.                     }
  2779.  
  2780.                     break;
  2781.                 }
  2782.                 case NativeMethods.WindowMessage.LeftButtonUp:
  2783.                 {
  2784.                     isDragging = false;
  2785.                     NativeMethods.ReleaseCapture();
  2786.                     UpdateThumbRectangle();
  2787.                     break;
  2788.                 }
  2789.  
  2790.                 case NativeMethods.WindowMessage.MouseMove:
  2791.                 {
  2792.                     if (isDragging)
  2793.                     {
  2794.                         // Calculate new bottom and top of thumb rect
  2795.                         int bottom = thumbRect.Bottom + (pt.Y - thumbOffsetY - thumbRect.Top);
  2796.                         int top = pt.Y - thumbOffsetY;
  2797.                         thumbRect = new System.Drawing.Rectangle(thumbRect.Left, top, thumbRect.Width, bottom - top);
  2798.                         if (thumbRect.Top < trackRect.Top)
  2799.                             thumbRect.Offset(0, trackRect.Top - thumbRect.Top);
  2800.                         else if (thumbRect.Bottom > trackRect.Bottom)
  2801.                             thumbRect.Offset(0, trackRect.Bottom - thumbRect.Bottom);
  2802.  
  2803.                         // Compute first item index based on thumb position
  2804.                         int maxFirstItem = end - start - pageSize; // Largest possible index for first item
  2805.                         int maxThumb = trackRect.Height - thumbRect.Height; // Largest possible thumb position
  2806.  
  2807.                         position = start + (thumbRect.Top - trackRect.Top +
  2808.                             maxThumb / (maxFirstItem * 2) ) * // Shift by half a row to avoid last row covered
  2809.                             maxFirstItem / maxThumb;
  2810.  
  2811.                         return true;
  2812.                     }
  2813.                     break;
  2814.                 }
  2815.             }
  2816.  
  2817.             // Was not handled
  2818.             return false;
  2819.         }
  2820.  
  2821.     }
  2822.     #endregion
  2823.  
  2824.     #region ComboBox Control
  2825.     /// <summary>Stores data for a combo box item</summary>
  2826.     public struct ComboBoxItem
  2827.     {
  2828.         public string ItemText;
  2829.         public object ItemData;
  2830.         public System.Drawing.Rectangle ItemRect;
  2831.         public bool IsItemVisible;
  2832.     }
  2833.  
  2834.     /// <summary>Combo box control</summary>
  2835.     public class ComboBox : Button
  2836.     {
  2837.         public const int MainLayer = 0;
  2838.         public const int ComboButtonLayer = 1;
  2839.         public const int DropdownLayer = 2;
  2840.         public const int SelectionLayer = 3;
  2841.         #region Event code
  2842.         public event EventHandler Changed;
  2843.         /// <summary>Create new button instance</summary>
  2844.         protected void RaiseChangedEvent(ComboBox sender, bool wasTriggeredByUser)
  2845.         {
  2846.             // Discard events triggered programatically if these types of events haven't been
  2847.             // enabled
  2848.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  2849.                 return;
  2850.  
  2851.             // Fire both the changed and clicked event
  2852.             base.RaiseClickEvent(sender, wasTriggeredByUser);
  2853.             if (Changed != null)
  2854.                 Changed(sender, EventArgs.Empty);
  2855.         }
  2856.         #endregion
  2857.         private bool isScrollBarInit;
  2858.  
  2859.         #region Instance data
  2860.         protected int selectedIndex;
  2861.         protected int focusedIndex;
  2862.         protected int dropHeight;
  2863.         protected ScrollBar scrollbarControl;
  2864.         protected int scrollWidth;
  2865.         protected bool isComboOpen;
  2866.         protected System.Drawing.Rectangle textRect;
  2867.         protected System.Drawing.Rectangle buttonRect;
  2868.         protected System.Drawing.Rectangle dropDownRect;
  2869.         protected System.Drawing.Rectangle dropDownTextRect;
  2870.         protected ArrayList itemList;
  2871.         #endregion
  2872.  
  2873.         /// <summary>Create new combo box control</summary>
  2874.         public ComboBox(Dialog parent) : base(parent)
  2875.         {
  2876.             // Store control type and parent dialog
  2877.             controlType = ControlType.ComboBox;
  2878.             parentDialog = parent;
  2879.             // Create the scrollbar control too
  2880.             scrollbarControl = new ScrollBar(parent);
  2881.  
  2882.             // Set some default items
  2883.             dropHeight = 100;
  2884.             scrollWidth = 16;
  2885.             selectedIndex = -1;
  2886.             focusedIndex = -1;
  2887.             isScrollBarInit = false;
  2888.  
  2889.             // Create the item list array
  2890.             itemList = new ArrayList();
  2891.         }
  2892.  
  2893.         /// <summary>Update the rectangles for the combo box control</summary>
  2894.         protected override void UpdateRectangles()
  2895.         {
  2896.             // Get bounding box
  2897.             base.UpdateRectangles();
  2898.  
  2899.             // Update the bounding box for the items
  2900.             buttonRect = new System.Drawing.Rectangle(boundingBox.Right - boundingBox.Height, boundingBox.Top,
  2901.                 boundingBox.Height, boundingBox.Height);
  2902.  
  2903.             textRect = boundingBox;
  2904.             textRect.Size = new System.Drawing.Size(textRect.Width - buttonRect.Width, textRect.Height);
  2905.  
  2906.             dropDownRect = textRect;
  2907.             dropDownRect.Offset(0, (int)(0.9f * textRect.Height));
  2908.             dropDownRect.Size = new System.Drawing.Size(dropDownRect.Width - scrollWidth, dropDownRect.Height + dropHeight);
  2909.  
  2910.             // Scale it down slightly
  2911.             System.Drawing.Point loc = dropDownRect.Location;
  2912.             System.Drawing.Size size = dropDownRect.Size;
  2913.  
  2914.             loc.X += (int)(0.1f * dropDownRect.Width);
  2915.             loc.Y += (int)(0.1f * dropDownRect.Height);
  2916.             size.Width -= (2 * (int)(0.1f * dropDownRect.Width));
  2917.             size.Height -= (2 * (int)(0.1f * dropDownRect.Height));
  2918.  
  2919.             dropDownTextRect = new System.Drawing.Rectangle(loc, size);
  2920.  
  2921.             // Update the scroll bars rects too
  2922.             scrollbarControl.SetLocation(dropDownRect.Right, dropDownRect.Top + 2);
  2923.             scrollbarControl.SetSize(scrollWidth, dropDownRect.Height - 2);
  2924.             FontNode fNode = DialogResourceManager.GetGlobalInstance().GetFontNode((int)(elementList[2] as Element).FontIndex);
  2925.             if ((fNode != null) && (fNode.Height > 0))
  2926.             {
  2927.                 scrollbarControl.PageSize = (int)(dropDownTextRect.Height / fNode.Height);
  2928.  
  2929.                 // The selected item may have been scrolled off the page.
  2930.                 // Ensure that it is in page again.
  2931.                 scrollbarControl.ShowItem(selectedIndex);
  2932.             }
  2933.         }
  2934.  
  2935.         /// <summary>Sets the drop height of this control</summary>
  2936.         public void SetDropHeight(int height) { dropHeight = height; UpdateRectangles(); }
  2937.         /// <summary>Sets the scroll bar width of this control</summary>
  2938.         public void SetScrollbarWidth(int width) { scrollWidth = width; UpdateRectangles(); }
  2939.         /// <summary>Can this control have focus</summary>
  2940.         public override bool CanHaveFocus { get { return (IsVisible && IsEnabled); } }
  2941.         /// <summary>Number of items current in the list</summary>
  2942.         public int NumberItems { get { return itemList.Count; } }
  2943.         /// <summary>Indexer for items in the list</summary>
  2944.         public ComboBoxItem this[int index]
  2945.         {
  2946.             get { return (ComboBoxItem)itemList[index]; }
  2947.         }
  2948.  
  2949.         /// <summary>Initialize the scrollbar control here</summary>
  2950.         public override void OnInitialize()
  2951.         {
  2952.             parentDialog.InitializeControl(scrollbarControl);
  2953.         }
  2954.  
  2955.         /// <summary>Called when focus leaves the control</summary>
  2956.         public override void OnFocusOut()
  2957.         {
  2958.             // Call base first
  2959.             base.OnFocusOut ();
  2960.             isComboOpen = false;
  2961.         }
  2962.         /// <summary>Called when the control's hotkey is pressed</summary>
  2963.         public override void OnHotKey()
  2964.         {
  2965.             if (isComboOpen)
  2966.                 return; // Nothing to do yet
  2967.  
  2968.             if (selectedIndex == -1)
  2969.                 return; // Nothing selected
  2970.  
  2971.             selectedIndex++;
  2972.             if (selectedIndex >= itemList.Count)
  2973.                 selectedIndex = 0;
  2974.  
  2975.             focusedIndex = selectedIndex;
  2976.             RaiseChangedEvent(this, true);
  2977.         }
  2978.  
  2979.  
  2980.         /// <summary>Called when the control needs to handle the keyboard</summary>
  2981.         public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  2982.         {
  2983.             const uint RepeatMask = (0x40000000);
  2984.  
  2985.             if (!IsEnabled || !IsVisible)
  2986.                 return false;
  2987.  
  2988.             // Let the scroll bar have a chance to handle it first
  2989.             if (scrollbarControl.HandleKeyboard(msg, wParam, lParam))
  2990.                 return true;
  2991.  
  2992.             switch (msg)
  2993.             {
  2994.                 case NativeMethods.WindowMessage.KeyDown:
  2995.                 {
  2996.                     switch((System.Windows.Forms.Keys)wParam.ToInt32())
  2997.                     {
  2998.                         case System.Windows.Forms.Keys.Return:
  2999.                         {
  3000.                             if (isComboOpen)
  3001.                             {
  3002.                                 if (selectedIndex != focusedIndex)
  3003.                                 {
  3004.                                     selectedIndex = focusedIndex;
  3005.                                     RaiseChangedEvent(this, true);
  3006.                                 }
  3007.                                 isComboOpen = false;
  3008.  
  3009.                                 if (!Parent.IsUsingKeyboardInput)
  3010.                                     Dialog.ClearFocus();
  3011.  
  3012.                                 return true;
  3013.                             }
  3014.                             break;
  3015.                         }
  3016.                         case System.Windows.Forms.Keys.F4:
  3017.                         {
  3018.                             // Filter out auto repeats
  3019.                             if ((lParam.ToInt32() & RepeatMask) != 0)
  3020.                                 return true;
  3021.  
  3022.                             isComboOpen = !isComboOpen;
  3023.                             if (!isComboOpen)
  3024.                             {
  3025.                                 RaiseChangedEvent(this, true);
  3026.  
  3027.                                 if (!Parent.IsUsingKeyboardInput)
  3028.                                     Dialog.ClearFocus();
  3029.                             }
  3030.  
  3031.                             return true;
  3032.                         }
  3033.                         case System.Windows.Forms.Keys.Left:
  3034.                         case System.Windows.Forms.Keys.Up:
  3035.                         {
  3036.                             if (focusedIndex > 0)
  3037.                             {
  3038.                                 focusedIndex--;
  3039.                                 selectedIndex = focusedIndex;
  3040.                                 if (!isComboOpen)
  3041.                                     RaiseChangedEvent(this, true);
  3042.                             }
  3043.                             return true;
  3044.                         }
  3045.                         case System.Windows.Forms.Keys.Right:
  3046.                         case System.Windows.Forms.Keys.Down:
  3047.                         {
  3048.                             if (focusedIndex + 1 < (int)NumberItems)
  3049.                             {
  3050.                                 focusedIndex++;
  3051.                                 selectedIndex = focusedIndex;
  3052.                                 if (!isComboOpen)
  3053.                                     RaiseChangedEvent(this, true);
  3054.                             }
  3055.                             return true;
  3056.                         }
  3057.                     }
  3058.                     break;
  3059.                 }
  3060.             }
  3061.  
  3062.             return false;
  3063.         }
  3064.  
  3065.         /// <summary>Called when the control should handle the mouse</summary>
  3066.         public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
  3067.         {
  3068.             if (!IsEnabled || !IsVisible)
  3069.                 return false; // Nothing to do
  3070.  
  3071.             // Let the scroll bar handle it first
  3072.             if (scrollbarControl.HandleMouse(msg, pt, wParam, lParam))
  3073.                 return true;
  3074.  
  3075.             // Ok, scrollbar didn't handle it, move on
  3076.             switch(msg)
  3077.             {
  3078.                 case NativeMethods.WindowMessage.MouseMove:
  3079.                 {
  3080.                     if (isComboOpen && dropDownRect.Contains(pt))
  3081.                     {
  3082.                         // Determine which item has been selected
  3083.                         for (int i = 0; i < itemList.Count; i++)
  3084.                         {
  3085.                             ComboBoxItem cbi = (ComboBoxItem)itemList[i];
  3086.                             if (cbi.IsItemVisible && cbi.ItemRect.Contains(pt))
  3087.                             {
  3088.                                 focusedIndex = i;
  3089.                             }
  3090.                         }
  3091.                         return true;
  3092.                     }
  3093.                     break;
  3094.                 }
  3095.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  3096.                 case NativeMethods.WindowMessage.LeftButtonDown:
  3097.                 {
  3098.                     if (ContainsPoint(pt))
  3099.                     {
  3100.                         // Pressed while inside the control
  3101.                         isPressed = true;
  3102.                         NativeMethods.SetCapture(Parent.SampleFramework.Window);
  3103.  
  3104.                         if (!hasFocus)
  3105.                             Dialog.RequestFocus(this);
  3106.  
  3107.                         // Toggle dropdown
  3108.                         if (hasFocus)
  3109.                         {
  3110.                             isComboOpen = !isComboOpen;
  3111.                             if (!isComboOpen)
  3112.                             {
  3113.                                 if (!parentDialog.IsUsingKeyboardInput)
  3114.                                     Dialog.ClearFocus();
  3115.                             }
  3116.                         }
  3117.  
  3118.                         return true;
  3119.                     }
  3120.  
  3121.                     // Perhaps this click is within the dropdown
  3122.                     if (isComboOpen && dropDownRect.Contains(pt))
  3123.                     {
  3124.                         // Determine which item has been selected
  3125.                         for (int i = scrollbarControl.TrackPosition; i < itemList.Count; i++)
  3126.                         {
  3127.                             ComboBoxItem cbi = (ComboBoxItem)itemList[i];
  3128.                             if (cbi.IsItemVisible && cbi.ItemRect.Contains(pt))
  3129.                             {
  3130.                                 selectedIndex = focusedIndex = i;
  3131.                                 RaiseChangedEvent(this, true);
  3132.  
  3133.                                 isComboOpen = false;
  3134.  
  3135.                                 if (!parentDialog.IsUsingKeyboardInput)
  3136.                                     Dialog.ClearFocus();
  3137.  
  3138.                                 break;
  3139.                             }
  3140.                         }
  3141.                         return true;
  3142.                     }
  3143.                     // Mouse click not on main control or in dropdown, fire an event if needed
  3144.                     if (isComboOpen)
  3145.                     {
  3146.                         focusedIndex = selectedIndex;
  3147.                         RaiseChangedEvent(this, true);
  3148.                         isComboOpen = false;
  3149.                     }
  3150.  
  3151.                     // Make sure the control is no longer 'pressed'
  3152.                     isPressed = false;
  3153.  
  3154.                     // Release focus if appropriate
  3155.                     if (!parentDialog.IsUsingKeyboardInput)
  3156.                         Dialog.ClearFocus();
  3157.  
  3158.                     break;
  3159.                 }
  3160.                 case NativeMethods.WindowMessage.LeftButtonUp:
  3161.                 {
  3162.                     if (isPressed && ContainsPoint(pt))
  3163.                     {
  3164.                         // Button click
  3165.                         isPressed = false;
  3166.                         NativeMethods.ReleaseCapture();
  3167.                         return true;
  3168.                     }
  3169.                     break;
  3170.                 }
  3171.                 case NativeMethods.WindowMessage.MouseWheel:
  3172.                 {
  3173.                     int zdelta = (short)NativeMethods.HiWord((uint)wParam.ToInt32()) / Dialog.WheelDelta;
  3174.                     if (isComboOpen)
  3175.                     {
  3176.                         scrollbarControl.Scroll(-zdelta * System.Windows.Forms.SystemInformation.MouseWheelScrollLines);
  3177.                     }
  3178.                     else
  3179.                     {
  3180.                         if (zdelta > 0)
  3181.                         {
  3182.                             if (focusedIndex > 0)
  3183.                             {
  3184.                                 focusedIndex--;
  3185.                                 selectedIndex = focusedIndex;
  3186.                                 if (!isComboOpen)
  3187.                                 {
  3188.                                     RaiseChangedEvent(this, true);
  3189.                                 }
  3190.                             }
  3191.                         }
  3192.                         else
  3193.                         {
  3194.                             if (focusedIndex +1 < NumberItems)
  3195.                             {
  3196.                                 focusedIndex++;
  3197.                                 selectedIndex = focusedIndex;
  3198.                                 if (!isComboOpen)
  3199.                                 {
  3200.                                     RaiseChangedEvent(this, true);
  3201.                                 }
  3202.                             }
  3203.                         }
  3204.                     }
  3205.                     return true;
  3206.                 }
  3207.             }
  3208.  
  3209.             // Didn't handle it
  3210.             return false;
  3211.         }
  3212.  
  3213.         /// <summary>Called when the control should be rendered</summary>
  3214.         public override void Render(Device device, float elapsedTime)
  3215.         {
  3216.             ControlState state = ControlState.Normal;
  3217.             if (!isComboOpen)
  3218.                 state = ControlState.Hidden;
  3219.  
  3220.             // Dropdown box
  3221.             Element e = elementList[ComboBox.DropdownLayer] as Element;
  3222.             
  3223.             // If we have not initialized the scroll bar page size,
  3224.             // do that now.
  3225.             if (!isScrollBarInit)
  3226.             {
  3227.                 FontNode fNode = DialogResourceManager.GetGlobalInstance().GetFontNode((int)e.FontIndex);
  3228.                 if ((fNode != null) && (fNode.Height > 0))
  3229.                     scrollbarControl.PageSize = (int)(dropDownTextRect.Height / fNode.Height);
  3230.                 else
  3231.                     scrollbarControl.PageSize = dropDownTextRect.Height;
  3232.  
  3233.                 isScrollBarInit = true;
  3234.             }
  3235.  
  3236.             if (isComboOpen)
  3237.                 scrollbarControl.Render(device, elapsedTime);
  3238.  
  3239.             // Blend current color
  3240.             e.TextureColor.Blend(state, elapsedTime);
  3241.             e.FontColor.Blend(state, elapsedTime);
  3242.             parentDialog.DrawSprite(e, dropDownRect);
  3243.  
  3244.             // Selection outline
  3245.             Element selectionElement = elementList[ComboBox.SelectionLayer] as Element;
  3246.             selectionElement.TextureColor.Current = e.TextureColor.Current;
  3247.             selectionElement.FontColor.Current = selectionElement.FontColor.States[(int)ControlState.Normal];
  3248.  
  3249.             FontNode font = DialogResourceManager.GetGlobalInstance().GetFontNode((int)e.FontIndex);
  3250.             int currentY = dropDownTextRect.Top;
  3251.             int remainingHeight = dropDownTextRect.Height;
  3252.  
  3253.             for (int i = scrollbarControl.TrackPosition; i < itemList.Count; i++)
  3254.             {
  3255.                 ComboBoxItem cbi = (ComboBoxItem)itemList[i];
  3256.  
  3257.                 // Make sure there's room left in the dropdown
  3258.                 remainingHeight -= (int)font.Height;
  3259.                 if (remainingHeight < 0)
  3260.                 {
  3261.                     // Not visible, store that item
  3262.                     cbi.IsItemVisible = false;
  3263.                     itemList[i] = cbi; // Store this back in list
  3264.                     continue;
  3265.                 }
  3266.  
  3267.                 cbi.ItemRect = new System.Drawing.Rectangle(dropDownTextRect.Left, currentY,
  3268.                     dropDownTextRect.Width, (int)font.Height);
  3269.                 cbi.IsItemVisible = true;
  3270.                 currentY += (int)font.Height;
  3271.                 itemList[i] = cbi; // Store this back in list
  3272.  
  3273.                 if (isComboOpen)
  3274.                 {
  3275.                     if (focusedIndex == i)
  3276.                     {
  3277.                         System.Drawing.Rectangle rect = new System.Drawing.Rectangle(
  3278.                             dropDownRect.Left, cbi.ItemRect.Top - 2, dropDownRect.Width,
  3279.                             cbi.ItemRect.Height + 4);
  3280.                         parentDialog.DrawSprite(selectionElement, rect);
  3281.                         parentDialog.DrawText(cbi.ItemText, selectionElement, cbi.ItemRect);
  3282.                     }
  3283.                     else
  3284.                     {
  3285.                         parentDialog.DrawText(cbi.ItemText, e, cbi.ItemRect);
  3286.                     }
  3287.                 }
  3288.             }
  3289.  
  3290.             int offsetX = 0;
  3291.             int offsetY = 0;
  3292.  
  3293.             state = ControlState.Normal;
  3294.             if (IsVisible == false)
  3295.                 state = ControlState.Hidden;
  3296.             else if (IsEnabled == false)
  3297.                 state = ControlState.Disabled;
  3298.             else if (isPressed)
  3299.             {
  3300.                 state = ControlState.Pressed;
  3301.                 offsetX = 1;
  3302.                 offsetY = 2;
  3303.             }
  3304.             else if (isMouseOver)
  3305.             {
  3306.                 state = ControlState.MouseOver;
  3307.                 offsetX = -1;
  3308.                 offsetY = -2;
  3309.             }
  3310.             else if (hasFocus)
  3311.                 state = ControlState.Focus;
  3312.  
  3313.             float blendRate = (state == ControlState.Pressed) ? 0.0f : 0.8f;
  3314.  
  3315.             // Button
  3316.             e = elementList[ComboBox.ComboButtonLayer] as Element;
  3317.             
  3318.             // Blend current color
  3319.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  3320.             
  3321.             System.Drawing.Rectangle windowRect = buttonRect;
  3322.             windowRect.Offset(offsetX, offsetY);
  3323.             // Draw sprite
  3324.             parentDialog.DrawSprite(e, windowRect);
  3325.  
  3326.             if (isComboOpen)
  3327.                 state = ControlState.Pressed;
  3328.  
  3329.             // Main text box
  3330.             e = elementList[ComboBox.MainLayer] as Element;
  3331.             
  3332.             // Blend current color
  3333.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  3334.             e.FontColor.Blend(state, elapsedTime, blendRate);
  3335.  
  3336.             // Draw sprite
  3337.             parentDialog.DrawSprite(e, textRect);
  3338.  
  3339.             if (selectedIndex >= 0 && selectedIndex < itemList.Count)
  3340.             {
  3341.                 try
  3342.                 {
  3343.                     ComboBoxItem cbi = (ComboBoxItem)itemList[selectedIndex];
  3344.                     parentDialog.DrawText(cbi.ItemText, e, textRect);
  3345.                 }
  3346.                 catch {} // Ignore
  3347.             }
  3348.  
  3349.         }
  3350.  
  3351.         #region Item Controlling methods
  3352.         /// <summary>Adds an item to the combo box control</summary>
  3353.         public void AddItem(string text, object data)
  3354.         {
  3355.             if ((text == null) || (text.Length == 0))
  3356.                 throw new ArgumentNullException("text", "You must pass in a valid item name when adding a new item.");
  3357.  
  3358.             // Create a new item and add it
  3359.             ComboBoxItem newitem = new ComboBoxItem();
  3360.             newitem.ItemText = text;
  3361.             newitem.ItemData = data;
  3362.             itemList.Add(newitem);
  3363.  
  3364.             // Update the scrollbar with the new range
  3365.             scrollbarControl.SetTrackRange(0, itemList.Count);
  3366.  
  3367.             // If this is the only item in the list, it should be selected
  3368.             if (NumberItems == 1)
  3369.             {
  3370.                 selectedIndex = 0;
  3371.                 focusedIndex = 0;
  3372.                 RaiseChangedEvent(this, false);
  3373.             }
  3374.         }
  3375.  
  3376.         /// <summary>Removes an item at a particular index</summary>
  3377.         public void RemoveAt(int index)
  3378.         {
  3379.             // Remove the item
  3380.             itemList.RemoveAt(index);
  3381.  
  3382.             // Update the scrollbar with the new range
  3383.             scrollbarControl.SetTrackRange(0, itemList.Count);
  3384.  
  3385.             if (selectedIndex >= itemList.Count)
  3386.                 selectedIndex = itemList.Count - 1;
  3387.         }
  3388.  
  3389.         /// <summary>Removes all items from the control</summary>
  3390.         public void Clear()
  3391.         {
  3392.             // clear the list
  3393.             itemList.Clear();
  3394.  
  3395.             // Update scroll bar and index
  3396.             scrollbarControl.SetTrackRange(0, 1);
  3397.             focusedIndex = selectedIndex = -1;
  3398.         }
  3399.  
  3400.         /// <summary>Determines whether this control contains an item</summary>
  3401.         public bool ContainsItem(string text, int start)
  3402.         {
  3403.             return (FindItem(text, start) != -1);
  3404.         }
  3405.         /// <summary>Determines whether this control contains an item</summary>
  3406.         public bool ContainsItem(string text) { return ContainsItem(text, 0); }
  3407.  
  3408.         /// <summary>Gets the data for the selected item</summary>
  3409.         public object GetSelectedData()
  3410.         {
  3411.             if (selectedIndex < 0)
  3412.                 return null; // Nothing selected
  3413.  
  3414.             ComboBoxItem cbi = (ComboBoxItem)itemList[selectedIndex];
  3415.             return cbi.ItemData;
  3416.         }
  3417.  
  3418.         /// <summary>Gets the selected item</summary>
  3419.         public ComboBoxItem GetSelectedItem()
  3420.         {
  3421.             if (selectedIndex < 0)
  3422.                 throw new ArgumentOutOfRangeException("selectedIndex", "No item selected.");
  3423.  
  3424.             return (ComboBoxItem)itemList[selectedIndex];
  3425.         }
  3426.  
  3427.         /// <summary>Gets the data for an item</summary>
  3428.         public object GetItemData(string text)
  3429.         {
  3430.             int index = FindItem(text);
  3431.             if (index == -1)
  3432.                 return null; // no item
  3433.  
  3434.             ComboBoxItem cbi = (ComboBoxItem)itemList[index];
  3435.             return cbi.ItemData;
  3436.         }
  3437.  
  3438.         /// <summary>Finds an item in the list and returns the index</summary>
  3439.         protected int FindItem(string text, int start)
  3440.         {
  3441.             if ((text == null) || (text.Length == 0))
  3442.                 return -1;
  3443.  
  3444.             for(int i = start; i < itemList.Count; i++)
  3445.             {
  3446.                 ComboBoxItem cbi = (ComboBoxItem)itemList[i];
  3447.                 if (string.Compare(cbi.ItemText, text, true) == 0)
  3448.                 {
  3449.                     return i;
  3450.                 }
  3451.             }
  3452.  
  3453.             // Never found it
  3454.             return -1;
  3455.         }
  3456.         /// <summary>Finds an item in the list and returns the index</summary>
  3457.         protected int FindItem(string text) { return FindItem(text, 0); }
  3458.  
  3459.         /// <summary>Sets the selected item by index</summary>
  3460.         public void SetSelected(int index)
  3461.         {
  3462.             if (index >= NumberItems)
  3463.                 throw new ArgumentOutOfRangeException("index", "There are not enough items in the list to select this index.");
  3464.  
  3465.             focusedIndex = selectedIndex = index;
  3466.             RaiseChangedEvent(this, false);
  3467.         }
  3468.  
  3469.         /// <summary>Sets the selected item by text</summary>
  3470.         public void SetSelected(string text)
  3471.         {
  3472.             if ((text == null) || (text.Length == 0))
  3473.                 throw new ArgumentNullException("text", "You must pass in a valid item name when adding a new item.");
  3474.  
  3475.             int index = FindItem(text);
  3476.             if (index == -1)
  3477.                 throw new InvalidOperationException("This item could not be found.");
  3478.  
  3479.             focusedIndex = selectedIndex = index;
  3480.             RaiseChangedEvent(this, false);
  3481.         }
  3482.  
  3483.         /// <summary>Sets the selected item by data</summary>
  3484.         public void SetSelectedByData(object data)
  3485.         {
  3486.             for (int index = 0; index < itemList.Count; index++)
  3487.             {
  3488.                 ComboBoxItem cbi = (ComboBoxItem)itemList[index];
  3489.                 if (cbi.ItemData.ToString().Equals(data.ToString()))
  3490.                 {
  3491.                     focusedIndex = selectedIndex = index;
  3492.                     RaiseChangedEvent(this, false);
  3493.                 }
  3494.             }
  3495.  
  3496.             // Could not find this item.  Uncomment line below for debug information
  3497.             //System.Diagnostics.Debugger.Log(9,string.Empty, "Could not find an object with this data.\r\n");
  3498.         }
  3499.  
  3500.         #endregion
  3501.     }
  3502.     #endregion
  3503.  
  3504.     #region Slider Control
  3505.     /// <summary>Slider control</summary>
  3506.     public class Slider : Control
  3507.     {
  3508.         public const int TrackLayer = 0;
  3509.         public const int ButtonLayer = 1;
  3510.         #region Instance Data
  3511.         public event EventHandler ValueChanged;
  3512.         protected int currentValue; 
  3513.         protected int maxValue;
  3514.         protected int minValue;
  3515.         
  3516.         protected int dragX; // Mouse position at the start of the drag
  3517.         protected int dragOffset; // Drag offset from the center of the button
  3518.         protected int buttonX;
  3519.  
  3520.         protected bool isPressed;
  3521.         protected System.Drawing.Rectangle buttonRect;
  3522.  
  3523.         /// <summary>Slider's can always have focus</summary>
  3524.         public override bool CanHaveFocus { get { return true; }}
  3525.  
  3526.         /// <summary>Current value of the slider</summary>
  3527.         protected void RaiseValueChanged(Slider sender, bool wasTriggeredByUser)
  3528.         {
  3529.             // Discard events triggered programatically if these types of events haven't been
  3530.             // enabled
  3531.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  3532.                 return;
  3533.  
  3534.             if (ValueChanged != null)
  3535.                 ValueChanged(sender, EventArgs.Empty);
  3536.         }
  3537.         /// <summary>Current value of the slider</summary>
  3538.         public int Value { get { return currentValue; } set { SetValueInternal(value, false); } }
  3539.         /// <summary>Sets the range of the slider</summary>
  3540.         public void SetRange(int min, int max)
  3541.         {
  3542.             minValue = min;
  3543.             maxValue = max;
  3544.             SetValueInternal(currentValue, false);
  3545.         }
  3546.  
  3547.         /// <summary>Sets the value internally and fires the event if needed</summary>
  3548.         protected void SetValueInternal(int newValue, bool fromInput)
  3549.         {
  3550.             // Clamp to the range
  3551.             newValue = Math.Max(minValue, newValue);
  3552.             newValue = Math.Min(maxValue, newValue);
  3553.             if (newValue == currentValue)
  3554.                 return;
  3555.  
  3556.             // Update the value, the rects, then fire the events if necessar
  3557.             currentValue = newValue; 
  3558.             UpdateRectangles();
  3559.             RaiseValueChanged(this, fromInput);
  3560.         }
  3561.         #endregion
  3562.  
  3563.         /// <summary>Create new button instance</summary>
  3564.         public Slider(Dialog parent): base(parent)
  3565.         {
  3566.             controlType = ControlType.Slider;
  3567.             parentDialog = parent;
  3568.  
  3569.             isPressed = false;
  3570.             minValue = 0;
  3571.             maxValue = 100;
  3572.             currentValue = 50;
  3573.         }
  3574.  
  3575.         /// <summary>Does the control contain this point?</summary>
  3576.         public override bool ContainsPoint(System.Drawing.Point pt)
  3577.         {
  3578.             return boundingBox.Contains(pt) || buttonRect.Contains(pt);
  3579.         }
  3580.  
  3581.         /// <summary>Update the rectangles for the control</summary>
  3582.         protected override void UpdateRectangles()
  3583.         {
  3584.             // First get the bounding box
  3585.             base.UpdateRectangles ();
  3586.  
  3587.             // Create the button rect
  3588.             buttonRect = boundingBox;
  3589.             buttonRect.Width = buttonRect.Height; // Make it square
  3590.  
  3591.             // Offset it 
  3592.             buttonRect.Offset(-buttonRect.Width / 2, 0);
  3593.             buttonX = (int)((currentValue - minValue) * (float)boundingBox.Width / (maxValue - minValue) );
  3594.             buttonRect.Offset(buttonX, 0);
  3595.         }
  3596.  
  3597.         /// <summary>Gets a value from a position</summary>
  3598.         public int ValueFromPosition(int x)
  3599.         {
  3600.             float valuePerPixel = ((float)(maxValue - minValue) / (float)boundingBox.Width);
  3601.             return (int)(0.5f + minValue + valuePerPixel * (x - boundingBox.Left));
  3602.         }
  3603.  
  3604.         /// <summary>Handle mouse input input</summary>
  3605.         public override bool HandleMouse(Microsoft.Samples.DirectX.UtilityToolkit.NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
  3606.         {
  3607.             if (!IsEnabled || !IsVisible)
  3608.                 return false;
  3609.  
  3610.             switch(msg)
  3611.             {
  3612.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  3613.                 case NativeMethods.WindowMessage.LeftButtonDown:
  3614.                 {
  3615.                     if (buttonRect.Contains(pt))
  3616.                     {
  3617.                         // Pressed while inside the control
  3618.                         isPressed = true;
  3619.                         NativeMethods.SetCapture(Parent.SampleFramework.Window);
  3620.  
  3621.                         dragX = pt.X;
  3622.                         dragOffset = buttonX - dragX;
  3623.                         if (!hasFocus)
  3624.                             Dialog.RequestFocus(this);
  3625.                         
  3626.                         return true;
  3627.                     }
  3628.                     if (boundingBox.Contains(pt))
  3629.                     {
  3630.                         if (pt.X > buttonX + controlX)
  3631.                         {
  3632.                             SetValueInternal(currentValue + 1, true);
  3633.                             return true;
  3634.                         }
  3635.                         if (pt.X < buttonX + controlX)
  3636.                         {
  3637.                             SetValueInternal(currentValue - 1, true);
  3638.                             return true;
  3639.                         }
  3640.                     }
  3641.  
  3642.                     break;
  3643.                 }
  3644.                 case NativeMethods.WindowMessage.LeftButtonUp:
  3645.                 {
  3646.                     if (isPressed)
  3647.                     {
  3648.                         isPressed = false;
  3649.                         NativeMethods.ReleaseCapture();
  3650.                         Dialog.ClearFocus();
  3651.                         RaiseValueChanged(this, true);
  3652.                         return true;
  3653.                     }
  3654.                     break;
  3655.                 }
  3656.                 case NativeMethods.WindowMessage.MouseMove:
  3657.                 {
  3658.                     if (isPressed)
  3659.                     {
  3660.                         SetValueInternal(ValueFromPosition(controlX + pt.X + dragOffset), true);
  3661.                         return true;
  3662.                     }
  3663.                     break;
  3664.                 }
  3665.             }
  3666.             return false;
  3667.         }
  3668.  
  3669.         /// <summary>Handle keyboard input</summary>
  3670.         public override bool HandleKeyboard(Microsoft.Samples.DirectX.UtilityToolkit.NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  3671.         {
  3672.             if (!IsEnabled || !IsVisible)
  3673.                 return false;
  3674.  
  3675.             if (msg == NativeMethods.WindowMessage.KeyDown)
  3676.             {
  3677.                 switch((System.Windows.Forms.Keys)wParam.ToInt32())
  3678.                 {
  3679.                     case System.Windows.Forms.Keys.Home:
  3680.                         SetValueInternal(minValue, true);
  3681.                         return true;
  3682.                     case System.Windows.Forms.Keys.End:
  3683.                         SetValueInternal(maxValue, true);
  3684.                         return true;
  3685.                     case System.Windows.Forms.Keys.Prior:
  3686.                     case System.Windows.Forms.Keys.Left:
  3687.                     case System.Windows.Forms.Keys.Up:
  3688.                         SetValueInternal(currentValue - 1, true);
  3689.                         return true;
  3690.                     case System.Windows.Forms.Keys.Next:
  3691.                     case System.Windows.Forms.Keys.Right:
  3692.                     case System.Windows.Forms.Keys.Down:
  3693.                         SetValueInternal(currentValue + 1, true);
  3694.                         return true;
  3695.                 }
  3696.             }
  3697.  
  3698.             return false;
  3699.         }
  3700.  
  3701.     
  3702.         /// <summary>Render the slider</summary>
  3703.         public override void Render(Device device, float elapsedTime)
  3704.         {
  3705.             ControlState state = ControlState.Normal;
  3706.             if (IsVisible == false)
  3707.             {
  3708.                 state = ControlState.Hidden;
  3709.             }
  3710.             else if (IsEnabled == false)
  3711.             {
  3712.                 state = ControlState.Disabled;
  3713.             }
  3714.             else if (isPressed)
  3715.             {
  3716.                 state = ControlState.Pressed;
  3717.             }
  3718.             else if (isMouseOver)
  3719.             {
  3720.                 state = ControlState.MouseOver;
  3721.             }
  3722.             else if (hasFocus)
  3723.             {
  3724.                 state = ControlState.Focus;
  3725.             }
  3726.  
  3727.             float blendRate = (state == ControlState.Pressed) ? 0.0f : 0.8f;
  3728.  
  3729.             Element e = elementList[Slider.TrackLayer] as Element;
  3730.             
  3731.             // Blend current color
  3732.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  3733.             parentDialog.DrawSprite(e, boundingBox);
  3734.  
  3735.             e = elementList[Slider.ButtonLayer] as Element;
  3736.             // Blend current color
  3737.             e.TextureColor.Blend(state, elapsedTime, blendRate);
  3738.             parentDialog.DrawSprite(e, buttonRect);
  3739.         }
  3740.     }
  3741.     #endregion
  3742.  
  3743.     #region Listbox Control
  3744.  
  3745.     /// <summary>Style of the list box</summary>
  3746.     public enum ListBoxStyle
  3747.     {
  3748.         SingleSelection,
  3749.         Multiselection,
  3750.     }
  3751.  
  3752.     /// <summary>Stores data for a list box item</summary>
  3753.     public struct ListBoxItem
  3754.     {
  3755.         public string ItemText;
  3756.         public object ItemData;
  3757.         public System.Drawing.Rectangle ItemRect;
  3758.         public bool IsItemSelected;
  3759.     }
  3760.     /// <summary>List box control</summary>
  3761.     public class ListBox : Control
  3762.     {
  3763.         public const int MainLayer = 0;
  3764.         public const int SelectionLayer = 1;
  3765.  
  3766.         #region Event code
  3767.         public event EventHandler ContentsChanged;
  3768.         public event EventHandler DoubleClick;
  3769.         public event EventHandler Selection;
  3770.         /// <summary>Raises the contents changed event</summary>
  3771.         protected void RaiseContentsChangedEvent(ListBox sender, bool wasTriggeredByUser)
  3772.         {
  3773.             // Discard events triggered programatically if these types of events haven't been
  3774.             // enabled
  3775.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  3776.                 return;
  3777.  
  3778.             // Fire the event
  3779.             if (ContentsChanged != null)
  3780.                 ContentsChanged(sender, EventArgs.Empty);
  3781.         }
  3782.         /// <summary>Raises the double click event</summary>
  3783.         protected void RaiseDoubleClickEvent(ListBox sender, bool wasTriggeredByUser)
  3784.         {
  3785.             // Discard events triggered programatically if these types of events haven't been
  3786.             // enabled
  3787.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  3788.                 return;
  3789.  
  3790.             // Fire the event
  3791.             if (DoubleClick != null)
  3792.                 DoubleClick(sender, EventArgs.Empty);
  3793.         }
  3794.         /// <summary>Raises the selection event</summary>
  3795.         protected void RaiseSelectionEvent(ListBox sender, bool wasTriggeredByUser)
  3796.         {
  3797.             // Discard events triggered programatically if these types of events haven't been
  3798.             // enabled
  3799.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  3800.                 return;
  3801.  
  3802.             // Fire the event
  3803.             if (Selection != null)
  3804.                 Selection(sender, EventArgs.Empty);
  3805.         }
  3806.         #endregion
  3807.  
  3808.         #region Instance data
  3809.         private bool isScrollBarInit;
  3810.         protected System.Drawing.Rectangle textRect; // Text rendering bound
  3811.         protected System.Drawing.Rectangle selectionRect; // Selection box bound
  3812.         protected ScrollBar scrollbarControl; 
  3813.         protected int scrollWidth;
  3814.         protected int border;
  3815.         protected int margin;
  3816.         protected int textHeight; // Height of a single line of text
  3817.         protected int selectedIndex;
  3818.         protected int selectedStarted;
  3819.         protected bool isDragging;
  3820.         protected ListBoxStyle style;
  3821.  
  3822.         protected ArrayList itemList;
  3823.         #endregion
  3824.  
  3825.         /// <summary>Create a new list box control</summary>
  3826.         public ListBox(Dialog parent) : base(parent)
  3827.         {
  3828.             // Store control type and parent dialog
  3829.             controlType = ControlType.ListBox;
  3830.             parentDialog = parent;
  3831.             // Create the scrollbar control too
  3832.             scrollbarControl = new ScrollBar(parent);
  3833.  
  3834.             // Set some default items
  3835.             style = ListBoxStyle.SingleSelection;
  3836.             scrollWidth = 16;
  3837.             selectedIndex = -1;
  3838.             selectedStarted = 0;
  3839.             isDragging = false;
  3840.             margin = 5;
  3841.             border = 6;
  3842.             textHeight = 0;
  3843.             isScrollBarInit = false;
  3844.  
  3845.             // Create the item list array
  3846.             itemList = new ArrayList();
  3847.         }
  3848.  
  3849.         /// <summary>Update the rectangles for the list box control</summary>
  3850.         protected override void UpdateRectangles()
  3851.         {
  3852.             // Get bounding box
  3853.             base.UpdateRectangles();
  3854.  
  3855.             // Calculate the size of the selection rectangle
  3856.             selectionRect = boundingBox;
  3857.             selectionRect.Width -= scrollWidth;
  3858.             selectionRect.Inflate(-border, -border);
  3859.             textRect = selectionRect;
  3860.             textRect.Inflate(-margin, 0);
  3861.  
  3862.             // Update the scroll bars rects too
  3863.             scrollbarControl.SetLocation(boundingBox.Right - scrollWidth, boundingBox.Top);
  3864.             scrollbarControl.SetSize(scrollWidth, height);
  3865.             FontNode fNode = DialogResourceManager.GetGlobalInstance().GetFontNode((int)(elementList[0] as Element).FontIndex);
  3866.             if ((fNode != null) && (fNode.Height > 0))
  3867.             {
  3868.                 scrollbarControl.PageSize = (int)(textRect.Height / fNode.Height);
  3869.  
  3870.                 // The selected item may have been scrolled off the page.
  3871.                 // Ensure that it is in page again.
  3872.                 scrollbarControl.ShowItem(selectedIndex);
  3873.             }
  3874.         }
  3875.         /// <summary>Sets the scroll bar width of this control</summary>
  3876.         public void SetScrollbarWidth(int width) { scrollWidth = width; UpdateRectangles(); }
  3877.         /// <summary>Can this control have focus</summary>
  3878.         public override bool CanHaveFocus { get { return (IsVisible && IsEnabled); } }
  3879.         /// <summary>Sets the style of the listbox</summary>
  3880.         public ListBoxStyle Style { get { return style; } set { style = value; } } 
  3881.         /// <summary>Number of items current in the list</summary>
  3882.         public int NumberItems { get { return itemList.Count; } }
  3883.         /// <summary>Indexer for items in the list</summary>
  3884.         public ListBoxItem this[int index]
  3885.         {
  3886.             get { return (ListBoxItem)itemList[index]; }
  3887.         }
  3888.  
  3889.         /// <summary>Initialize the scrollbar control here</summary>
  3890.         public override void OnInitialize()
  3891.         {
  3892.             parentDialog.InitializeControl(scrollbarControl);
  3893.         }
  3894.  
  3895.  
  3896.         /// <summary>Called when the control needs to handle the keyboard</summary>
  3897.         public override bool HandleKeyboard(NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  3898.         {
  3899.             if (!IsEnabled || !IsVisible)
  3900.                 return false;
  3901.  
  3902.             // Let the scroll bar have a chance to handle it first
  3903.             if (scrollbarControl.HandleKeyboard(msg, wParam, lParam))
  3904.                 return true;
  3905.  
  3906.             switch (msg)
  3907.             {
  3908.                 case NativeMethods.WindowMessage.KeyDown:
  3909.                 {
  3910.                     switch((System.Windows.Forms.Keys)wParam.ToInt32())
  3911.                     {
  3912.                         case System.Windows.Forms.Keys.Up:
  3913.                         case System.Windows.Forms.Keys.Down:
  3914.                         case System.Windows.Forms.Keys.Next:
  3915.                         case System.Windows.Forms.Keys.Prior:
  3916.                         case System.Windows.Forms.Keys.Home:
  3917.                         case System.Windows.Forms.Keys.End:
  3918.                         {
  3919.                             // If no items exists, do nothing
  3920.                             if (itemList.Count == 0)
  3921.                                 return true;
  3922.  
  3923.                             int oldSelected = selectedIndex;
  3924.  
  3925.                             // Adjust selectedIndex
  3926.                             switch((System.Windows.Forms.Keys)wParam.ToInt32())
  3927.                             {
  3928.                                 case System.Windows.Forms.Keys.Up: --selectedIndex; break;
  3929.                                 case System.Windows.Forms.Keys.Down: ++selectedIndex; break;
  3930.                                 case System.Windows.Forms.Keys.Next: selectedIndex += scrollbarControl.PageSize - 1; break;
  3931.                                 case System.Windows.Forms.Keys.Prior: selectedIndex -= scrollbarControl.PageSize - 1; break;
  3932.                                 case System.Windows.Forms.Keys.Home: selectedIndex = 0; break;
  3933.                                 case System.Windows.Forms.Keys.End: selectedIndex = itemList.Count - 1; break;
  3934.                             }
  3935.  
  3936.                             // Clamp the item
  3937.                             if (selectedIndex < 0)
  3938.                                 selectedIndex = 0;
  3939.                             if (selectedIndex >= itemList.Count)
  3940.                                 selectedIndex = itemList.Count - 1;
  3941.  
  3942.                             // Did the selection change?
  3943.                             if (oldSelected != selectedIndex)
  3944.                             {
  3945.                                 if (style == ListBoxStyle.Multiselection)
  3946.                                 {
  3947.                                     // Clear all selection
  3948.                                     for(int i = 0; i < itemList.Count; i++)
  3949.                                     {
  3950.                                         ListBoxItem lbi = (ListBoxItem)itemList[i];
  3951.                                         lbi.IsItemSelected = false;
  3952.                                         itemList[i] = lbi;
  3953.                                     }
  3954.  
  3955.                                     // Is shift being held down?
  3956.                                     bool shiftDown = ((NativeMethods.GetAsyncKeyState
  3957.                                         ((int)System.Windows.Forms.Keys.ShiftKey) & 0x8000) != 0);
  3958.  
  3959.                                     if (shiftDown)
  3960.                                     {
  3961.                                         // Select all items from the start selection to current selected index
  3962.                                         int end = Math.Max(selectedStarted, selectedIndex);
  3963.                                         for(int i = Math.Min(selectedStarted, selectedIndex); i <= end; ++i)
  3964.                                         {
  3965.                                             ListBoxItem lbi = (ListBoxItem)itemList[i];
  3966.                                             lbi.IsItemSelected = true;
  3967.                                             itemList[i] = lbi;
  3968.                                         }
  3969.                                     }
  3970.                                     else
  3971.                                     {
  3972.                                         ListBoxItem lbi = (ListBoxItem)itemList[selectedIndex];
  3973.                                         lbi.IsItemSelected = true;
  3974.                                         itemList[selectedIndex] = lbi;
  3975.  
  3976.                                         // Update selection start
  3977.                                         selectedStarted = selectedIndex;
  3978.                                     }
  3979.  
  3980.                                 }
  3981.                                 else // Update selection start
  3982.                                     selectedStarted = selectedIndex;
  3983.  
  3984.                                 // adjust scrollbar
  3985.                                 scrollbarControl.ShowItem(selectedIndex);
  3986.                                 RaiseSelectionEvent(this, true);
  3987.                             }
  3988.                         }
  3989.                         return true;
  3990.                     }
  3991.                     break;
  3992.                 }
  3993.             }
  3994.  
  3995.             return false;
  3996.         }
  3997.  
  3998.         /// <summary>Called when the control should handle the mouse</summary>
  3999.         public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
  4000.         {
  4001.             const int ShiftModifier = 0x0004;
  4002.             const int ControlModifier = 0x0008;
  4003.  
  4004.             if (!IsEnabled || !IsVisible)
  4005.                 return false; // Nothing to do
  4006.  
  4007.             // First acquire focus
  4008.             if (msg == NativeMethods.WindowMessage.LeftButtonDown)
  4009.                 if (!hasFocus)
  4010.                     Dialog.RequestFocus(this);
  4011.  
  4012.  
  4013.             // Let the scroll bar handle it first
  4014.             if (scrollbarControl.HandleMouse(msg, pt, wParam, lParam))
  4015.                 return true;
  4016.  
  4017.             // Ok, scrollbar didn't handle it, move on
  4018.             switch(msg)
  4019.             {
  4020.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  4021.                 case NativeMethods.WindowMessage.LeftButtonDown:
  4022.                 {
  4023.                     // Check for clicks in the text area
  4024.                     if (itemList.Count > 0 && selectionRect.Contains(pt))
  4025.                     {
  4026.                         // Compute the index of the clicked item
  4027.                         int clicked = 0;
  4028.                         if (textHeight > 0)
  4029.                             clicked = scrollbarControl.TrackPosition + (pt.Y - textRect.Top) / textHeight;
  4030.                         else
  4031.                             clicked = -1;
  4032.  
  4033.                         // Only proceed if the click falls ontop of an item
  4034.                         if (clicked >= scrollbarControl.TrackPosition &&
  4035.                             clicked < itemList.Count &&
  4036.                             clicked < scrollbarControl.TrackPosition + scrollbarControl.PageSize )
  4037.                         {
  4038.                             NativeMethods.SetCapture(Parent.SampleFramework.Window);
  4039.                             isDragging = true;
  4040.  
  4041.                             // If this is a double click, fire off an event and exit
  4042.                             // since the first click would have taken care of the selection
  4043.                             // updating.
  4044.                             if (msg == NativeMethods.WindowMessage.LeftButtonDoubleClick)
  4045.                             {
  4046.                                 RaiseDoubleClickEvent(this, true);
  4047.                                 return true;
  4048.                             }
  4049.  
  4050.                             selectedIndex = clicked;
  4051.                             if ( (wParam.ToInt32() & ShiftModifier) == 0)
  4052.                                 selectedStarted = selectedIndex; // Shift isn't down
  4053.  
  4054.                             // If this is a multi-selection listbox, update per-item
  4055.                             // selection data.
  4056.                             if (style == ListBoxStyle.Multiselection)
  4057.                             {
  4058.                                 // Determine behavior based on the state of Shift and Ctrl
  4059.                                 ListBoxItem selectedItem = (ListBoxItem)itemList[selectedIndex];
  4060.                                 if ((wParam.ToInt32() & (ShiftModifier | ControlModifier)) == ControlModifier)
  4061.                                 {
  4062.                                     // Control click, reverse the selection
  4063.                                     selectedItem.IsItemSelected = !selectedItem.IsItemSelected;
  4064.                                     itemList[selectedIndex] = selectedItem;
  4065.                                 }
  4066.                                 else if ((wParam.ToInt32() & (ShiftModifier | ControlModifier)) == ShiftModifier)
  4067.                                 {
  4068.                                     // Shift click. Set the selection for all items
  4069.                                     // from last selected item to the current item.
  4070.                                     // Clear everything else.
  4071.                                     int begin = Math.Min(selectedStarted, selectedIndex);
  4072.                                     int end = Math.Max(selectedStarted, selectedIndex);
  4073.  
  4074.                                     // Unselect everthing before the beginning
  4075.                                     for(int i = 0; i < begin; ++i)
  4076.                                     {
  4077.                                         ListBoxItem lb = (ListBoxItem)itemList[i];
  4078.                                         lb.IsItemSelected = false;
  4079.                                         itemList[i] = lb;
  4080.                                     }
  4081.                                     // unselect everything after the end
  4082.                                     for(int i = end + 1; i < itemList.Count; ++i)
  4083.                                     {
  4084.                                         ListBoxItem lb = (ListBoxItem)itemList[i];
  4085.                                         lb.IsItemSelected = false;
  4086.                                         itemList[i] = lb;
  4087.                                     }
  4088.  
  4089.                                     // Select everything between
  4090.                                     for(int i = begin; i <= end; ++i)
  4091.                                     {
  4092.                                         ListBoxItem lb = (ListBoxItem)itemList[i];
  4093.                                         lb.IsItemSelected = true;
  4094.                                         itemList[i] = lb;
  4095.                                     }
  4096.                                 }
  4097.                                 else if ((wParam.ToInt32() & (ShiftModifier | ControlModifier)) == (ShiftModifier | ControlModifier))
  4098.                                 {
  4099.                                     // Control-Shift-click.
  4100.  
  4101.                                     // The behavior is:
  4102.                                     //   Set all items from selectedStarted to selectedIndex to
  4103.                                     //     the same state as selectedStarted, not including selectedIndex.
  4104.                                     //   Set selectedIndex to selected.
  4105.                                     int begin = Math.Min(selectedStarted, selectedIndex);
  4106.                                     int end = Math.Max(selectedStarted, selectedIndex);
  4107.  
  4108.                                     // The two ends do not need to be set here.
  4109.                                     bool isLastSelected = ((ListBoxItem)itemList[selectedStarted]).IsItemSelected;
  4110.  
  4111.                                     for (int i = begin + 1; i < end; ++i)
  4112.                                     {
  4113.                                         ListBoxItem lb = (ListBoxItem)itemList[i];
  4114.                                         lb.IsItemSelected = isLastSelected;
  4115.                                         itemList[i] = lb;
  4116.                                     }
  4117.  
  4118.                                     selectedItem.IsItemSelected = true;
  4119.                                     itemList[selectedIndex] = selectedItem;
  4120.  
  4121.                                     // Restore selectedIndex to the previous value
  4122.                                     // This matches the Windows behavior
  4123.  
  4124.                                     selectedIndex = selectedStarted;
  4125.                                 }
  4126.                                 else
  4127.                                 {
  4128.                                     // Simple click.  Clear all items and select the clicked
  4129.                                     // item.
  4130.                                     for(int i = 0; i < itemList.Count; ++i)
  4131.                                     {
  4132.                                         ListBoxItem lb = (ListBoxItem)itemList[i];
  4133.                                         lb.IsItemSelected = false;
  4134.                                         itemList[i] = lb;
  4135.                                     }
  4136.                                     selectedItem.IsItemSelected = true;
  4137.                                     itemList[selectedIndex] = selectedItem;
  4138.                                 }
  4139.                             } // End of multi-selection case
  4140.                             RaiseSelectionEvent(this, true);
  4141.                         }
  4142.                         return true;
  4143.                     }
  4144.                     break;
  4145.                 }
  4146.                 case NativeMethods.WindowMessage.LeftButtonUp:
  4147.                 {
  4148.                     NativeMethods.ReleaseCapture();
  4149.                     isDragging = false;
  4150.  
  4151.                     if (selectedIndex != -1)
  4152.                     {
  4153.                         // Set all items between selectedStarted and selectedIndex to
  4154.                         // the same state as selectedStarted
  4155.                         int end = Math.Max(selectedStarted, selectedIndex);
  4156.                         for (int i = Math.Min(selectedStarted, selectedIndex) + 1; i < end; ++i)
  4157.                         {
  4158.                             ListBoxItem lb = (ListBoxItem)itemList[i];
  4159.                             lb.IsItemSelected = ((ListBoxItem)itemList[selectedStarted]).IsItemSelected;
  4160.                             itemList[i] = lb;
  4161.                         }
  4162.                         ListBoxItem lbs = (ListBoxItem)itemList[selectedIndex];
  4163.                         lbs.IsItemSelected = ((ListBoxItem)itemList[selectedStarted]).IsItemSelected;
  4164.                         itemList[selectedIndex] = lbs;
  4165.  
  4166.                         // If selectedStarted and selectedIndex are not the same,
  4167.                         // the user has dragged the mouse to make a selection.
  4168.                         // Notify the application of this.
  4169.                         if (selectedIndex != selectedStarted)
  4170.                             RaiseSelectionEvent(this, true);
  4171.                     }
  4172.                     break;
  4173.                 }
  4174.                 case NativeMethods.WindowMessage.MouseWheel:
  4175.                 {
  4176.                     int lines = System.Windows.Forms.SystemInformation.MouseWheelScrollLines;
  4177.                     int scrollAmount = (int)(NativeMethods.HiWord((uint)wParam.ToInt32()) / Dialog.WheelDelta * lines);
  4178.                     scrollbarControl.Scroll(-scrollAmount);
  4179.                     break;
  4180.                 }
  4181.  
  4182.                 case NativeMethods.WindowMessage.MouseMove:
  4183.                 {
  4184.                     if (isDragging)
  4185.                     {
  4186.                         // compute the index of the item below the cursor
  4187.                         int itemIndex = -1;
  4188.                         if (textHeight > 0)
  4189.                             itemIndex = scrollbarControl.TrackPosition + (pt.Y - textRect.Top) / textHeight;
  4190.  
  4191.                         // Only proceed if the cursor is on top of an item
  4192.                         if (itemIndex >= scrollbarControl.TrackPosition &&
  4193.                             itemIndex < itemList.Count &&
  4194.                             itemIndex < scrollbarControl.TrackPosition + scrollbarControl.PageSize)
  4195.                         {
  4196.                             selectedIndex = itemIndex;
  4197.                             RaiseSelectionEvent(this, true);
  4198.                         }
  4199.                         else if (itemIndex < scrollbarControl.TrackPosition)
  4200.                         {
  4201.                             // User drags the mouse above window top
  4202.                             scrollbarControl.Scroll(-1);
  4203.                             selectedIndex = scrollbarControl.TrackPosition;
  4204.                             RaiseSelectionEvent(this, true);
  4205.                         }
  4206.                         else if (itemIndex >= scrollbarControl.TrackPosition + scrollbarControl.PageSize)
  4207.                         {
  4208.                             // User drags the mouse below the window bottom
  4209.                             scrollbarControl.Scroll(1);
  4210.                             selectedIndex = Math.Min(itemList.Count, scrollbarControl.TrackPosition + scrollbarControl.PageSize - 1);
  4211.                             RaiseSelectionEvent(this, true);
  4212.                         }
  4213.                     }
  4214.                     break;
  4215.                 }
  4216.             }
  4217.  
  4218.             // Didn't handle it
  4219.             return false;
  4220.         }
  4221.  
  4222.         /// <summary>Called when the control should be rendered</summary>
  4223.         public override void Render(Device device, float elapsedTime)
  4224.         {
  4225.             if (!IsVisible)
  4226.                 return; // Nothing to render
  4227.             
  4228.             Element e = elementList[ListBox.MainLayer] as Element;
  4229.  
  4230.             // Blend current color
  4231.             e.TextureColor.Blend(ControlState.Normal, elapsedTime);
  4232.             e.FontColor.Blend(ControlState.Normal, elapsedTime);
  4233.             
  4234.             Element selectedElement = elementList[ListBox.SelectionLayer] as Element;
  4235.  
  4236.             // Blend current color
  4237.             selectedElement.TextureColor.Blend(ControlState.Normal, elapsedTime);
  4238.             selectedElement.FontColor.Blend(ControlState.Normal, elapsedTime);
  4239.  
  4240.             parentDialog.DrawSprite(e, boundingBox);
  4241.  
  4242.             // Render the text
  4243.             if (itemList.Count > 0)
  4244.             {
  4245.                 // Find out the height of a single line of text
  4246.                 System.Drawing.Rectangle rc = textRect;
  4247.                 System.Drawing.Rectangle sel = selectionRect;
  4248.                 rc.Height = (int)(DialogResourceManager.GetGlobalInstance().GetFontNode((int)e.FontIndex).Height);
  4249.                 textHeight = rc.Height;
  4250.  
  4251.                 // If we have not initialized the scroll bar page size,
  4252.                 // do that now.
  4253.                 if (!isScrollBarInit)
  4254.                 {
  4255.                     if (textHeight > 0)
  4256.                         scrollbarControl.PageSize = (int)(textRect.Height / textHeight);
  4257.                     else
  4258.                         scrollbarControl.PageSize = textRect.Height;
  4259.  
  4260.                     isScrollBarInit = true;
  4261.                 }
  4262.                 rc.Width = textRect.Width;
  4263.                 for (int i = scrollbarControl.TrackPosition; i < itemList.Count; ++i)
  4264.                 {
  4265.                     if (rc.Bottom > textRect.Bottom)
  4266.                         break;
  4267.  
  4268.                     ListBoxItem lb = (ListBoxItem)itemList[i];
  4269.  
  4270.                     // Determine if we need to render this item with the
  4271.                     // selected element.
  4272.                     bool isSelectedStyle = false;
  4273.  
  4274.                     if ( (selectedIndex == i) && (style == ListBoxStyle.SingleSelection) )
  4275.                         isSelectedStyle = true;
  4276.                     else if (style == ListBoxStyle.Multiselection)
  4277.                     {
  4278.                         if (isDragging && ( ( i >= selectedIndex && i < selectedStarted) || 
  4279.                             (i <= selectedIndex && i > selectedStarted) ) )
  4280.                         {
  4281.                             ListBoxItem selStart = (ListBoxItem)itemList[selectedStarted];
  4282.                             isSelectedStyle = selStart.IsItemSelected;
  4283.                         }
  4284.                         else
  4285.                             isSelectedStyle = lb.IsItemSelected;
  4286.                     }
  4287.  
  4288.                     // Now render the text
  4289.                     if (isSelectedStyle)
  4290.                     {
  4291.                         sel.Location = new System.Drawing.Point(sel.Left, rc.Top); 
  4292.                         sel.Height = rc.Height;
  4293.                         parentDialog.DrawSprite(selectedElement, sel);
  4294.                         parentDialog.DrawText(lb.ItemText, selectedElement, rc);
  4295.                     }
  4296.                     else
  4297.                         parentDialog.DrawText(lb.ItemText, e, rc);
  4298.  
  4299.                     rc.Offset(0, textHeight);
  4300.                 }
  4301.             }
  4302.  
  4303.             // Render the scrollbar finally
  4304.             scrollbarControl.Render(device, elapsedTime);
  4305.         }
  4306.  
  4307.         
  4308.         #region Item Controlling methods
  4309.         /// <summary>Adds an item to the list box control</summary>
  4310.         public void AddItem(string text, object data)
  4311.         {
  4312.             if ((text == null) || (text.Length == 0))
  4313.                 throw new ArgumentNullException("text", "You must pass in a valid item name when adding a new item.");
  4314.  
  4315.             // Create a new item and add it
  4316.             ListBoxItem newitem = new ListBoxItem();
  4317.             newitem.ItemText = text;
  4318.             newitem.ItemData = data;
  4319.             newitem.IsItemSelected = false;
  4320.             itemList.Add(newitem);
  4321.  
  4322.             // Update the scrollbar with the new range
  4323.             scrollbarControl.SetTrackRange(0, itemList.Count);
  4324.         }
  4325.         /// <summary>Inserts an item to the list box control</summary>
  4326.         public void InsertItem(int index, string text, object data)
  4327.         {
  4328.             if ((text == null) || (text.Length == 0))
  4329.                 throw new ArgumentNullException("text", "You must pass in a valid item name when adding a new item.");
  4330.  
  4331.             // Create a new item and insert it
  4332.             ListBoxItem newitem = new ListBoxItem();
  4333.             newitem.ItemText = text;
  4334.             newitem.ItemData = data;
  4335.             newitem.IsItemSelected = false;
  4336.             itemList.Insert(index, newitem);
  4337.  
  4338.             // Update the scrollbar with the new range
  4339.             scrollbarControl.SetTrackRange(0, itemList.Count);
  4340.         }
  4341.  
  4342.         /// <summary>Removes an item at a particular index</summary>
  4343.         public void RemoveAt(int index)
  4344.         {
  4345.             // Remove the item
  4346.             itemList.RemoveAt(index);
  4347.  
  4348.             // Update the scrollbar with the new range
  4349.             scrollbarControl.SetTrackRange(0, itemList.Count);
  4350.  
  4351.             if (selectedIndex >= itemList.Count)
  4352.                 selectedIndex = itemList.Count - 1;
  4353.  
  4354.             RaiseSelectionEvent(this, true);
  4355.         }
  4356.  
  4357.         /// <summary>Removes all items from the control</summary>
  4358.         public void Clear()
  4359.         {
  4360.             // clear the list
  4361.             itemList.Clear();
  4362.  
  4363.             // Update scroll bar and index
  4364.             scrollbarControl.SetTrackRange(0, 1);
  4365.             selectedIndex = -1;
  4366.         }
  4367.  
  4368.         /// <summary>
  4369.         /// For single-selection listbox, returns the index of the selected item.
  4370.         /// For multi-selection, returns the first selected item after the previousSelected position.
  4371.         /// To search for the first selected item, the app passes -1 for previousSelected.  For
  4372.         /// subsequent searches, the app passes the returned index back to GetSelectedIndex as.
  4373.         /// previousSelected.
  4374.         /// Returns -1 on error or if no item is selected.
  4375.         /// </summary>
  4376.         public int GetSelectedIndex(int previousSelected)
  4377.         {
  4378.             if (previousSelected < -1)
  4379.                 return -1;
  4380.  
  4381.             if (style == ListBoxStyle.Multiselection)
  4382.             {
  4383.                 // Multiple selections enabled.  Search for the next item with the selected flag
  4384.                 for (int i = previousSelected + 1; i < itemList.Count; ++i)
  4385.                 {
  4386.                     ListBoxItem lbi = (ListBoxItem)itemList[i];
  4387.                     if (lbi.IsItemSelected)
  4388.                         return i;
  4389.                 }
  4390.  
  4391.                 return -1;
  4392.             }
  4393.             else
  4394.             {
  4395.                 // Single selection
  4396.                 return selectedIndex;
  4397.             }
  4398.         }
  4399.         /// <summary>Gets the selected item</summary>
  4400.         public ListBoxItem GetSelectedItem(int previousSelected)
  4401.         {
  4402.             return (ListBoxItem)itemList[GetSelectedIndex(previousSelected)];
  4403.         }
  4404.         /// <summary>Gets the selected item</summary>
  4405.         public ListBoxItem GetSelectedItem() { return GetSelectedItem(-1); }
  4406.  
  4407.         /// <summary>Sets the border and margin sizes</summary>
  4408.         public void SetBorder(int borderSize, int marginSize)
  4409.         {
  4410.             border = borderSize;
  4411.             margin = marginSize;
  4412.             UpdateRectangles();
  4413.         }
  4414.  
  4415.         /// <summary>Selects this item</summary>
  4416.         public void SelectItem(int newIndex)
  4417.         {
  4418.             if (itemList.Count == 0)
  4419.                 return; // If no items exist there's nothing to do
  4420.  
  4421.             int oldSelected = selectedIndex;
  4422.  
  4423.             // Select the new item
  4424.             selectedIndex = newIndex;
  4425.  
  4426.             // Clamp the item
  4427.             if (selectedIndex < 0)
  4428.                 selectedIndex = 0;
  4429.             if (selectedIndex > itemList.Count)
  4430.                 selectedIndex = itemList.Count - 1;
  4431.  
  4432.             // Did the selection change?
  4433.             if (oldSelected != selectedIndex)
  4434.             {
  4435.                 if (style == ListBoxStyle.Multiselection)
  4436.                 {
  4437.                     ListBoxItem lbi = (ListBoxItem)itemList[selectedIndex];
  4438.                     lbi.IsItemSelected = true;
  4439.                     itemList[selectedIndex] = lbi;
  4440.                 }
  4441.  
  4442.                 // Update selection start
  4443.                 selectedStarted = selectedIndex;
  4444.  
  4445.                 // adjust scrollbar
  4446.                 scrollbarControl.ShowItem(selectedIndex);
  4447.             }
  4448.             RaiseSelectionEvent(this, true);
  4449.         }
  4450.         #endregion
  4451.     }
  4452.     #endregion
  4453.  
  4454.     /// <summary>A basic edit box</summary>
  4455.     public class EditBox : Control
  4456.     {
  4457.         #region Element layers
  4458.         public const int TextLayer = 0;
  4459.         public const int TopLeftBorder = 1;
  4460.         public const int TopBorder = 2;
  4461.         public const int TopRightBorder = 3;
  4462.         public const int LeftBorder = 4;
  4463.         public const int RightBorder = 5;
  4464.         public const int LowerLeftBorder = 6;
  4465.         public const int LowerBorder = 7;
  4466.         public const int LowerRightBorder = 8;
  4467.         #endregion
  4468.  
  4469.         #region Event code
  4470.         public event EventHandler Changed;
  4471.         public event EventHandler Enter;
  4472.         /// <summary>Raises the changed event</summary>
  4473.         protected void RaiseChangedEvent(EditBox sender, bool wasTriggeredByUser)
  4474.         {
  4475.             // Discard events triggered programatically if these types of events haven't been
  4476.             // enabled
  4477.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  4478.                 return;
  4479.  
  4480.             if (Changed != null)
  4481.                 Changed(sender, EventArgs.Empty);
  4482.         }
  4483.         /// <summary>Raises the Enter event</summary>
  4484.         protected void RaiseEnterEvent(EditBox sender, bool wasTriggeredByUser)
  4485.         {
  4486.             // Discard events triggered programatically if these types of events haven't been
  4487.             // enabled
  4488.             if (!Parent.IsUsingNonUserEvents && !wasTriggeredByUser)
  4489.                 return;
  4490.  
  4491.             if (Enter != null)
  4492.                 Enter(sender, EventArgs.Empty);
  4493.         }
  4494.         #endregion
  4495.  
  4496.         #region Class Data
  4497.         protected System.Windows.Forms.RichTextBox textData; // Text data
  4498.         protected int border; // Border of the window
  4499.         protected int spacing; // Spacing between the text and the edge of border
  4500.         protected System.Drawing.Rectangle textRect; // Bounding rectangle for the text
  4501.         protected System.Drawing.Rectangle[] elementRects = new System.Drawing.Rectangle[9];
  4502.         protected double blinkTime; // Caret blink time in milliseconds
  4503.         protected double lastBlink; // Last timestamp of caret blink
  4504.         protected bool isCaretOn; // Flag to indicate whether caret is currently visible
  4505.         protected int caretPosition; // Caret position, in characters
  4506.         protected bool isInsertMode; // If true, control is in insert mode. Else, overwrite mode.
  4507.         protected int firstVisible;  // First visible character in the edit control
  4508.         protected ColorValue textColor; // Text color
  4509.         protected ColorValue selectedTextColor; // Selected Text color
  4510.         protected ColorValue selectedBackColor; // Selected background color
  4511.         protected ColorValue caretColor; // Caret color
  4512.  
  4513.         // Mouse-specific
  4514.         protected bool isMouseDragging; // True to indicate the drag is in progress
  4515.  
  4516.         protected static bool isHidingCaret; // If true, we don't render the caret.
  4517.         
  4518.         #endregion
  4519.  
  4520.         #region Simple overrides/properties/methods
  4521.         /// <summary>Can the edit box have focus</summary>
  4522.         public override bool CanHaveFocus { get { return (IsVisible && IsEnabled); } }
  4523.         /// <summary>Update the spacing</summary>
  4524.         public void SetSpacing(int space) { spacing = space; UpdateRectangles(); }
  4525.         /// <summary>Update the border</summary>
  4526.         public void SetBorderWidth(int b) { border = b; UpdateRectangles(); }
  4527.         /// <summary>Update the text color</summary>
  4528.         public void SetTextColor(ColorValue color) { textColor = color; }
  4529.         /// <summary>Update the text selected color</summary>
  4530.         public void SetSelectedTextColor(ColorValue color) { selectedTextColor = color; }
  4531.         /// <summary>Update the selected background color</summary>
  4532.         public void SetSelectedBackColor(ColorValue color) { selectedBackColor = color; }
  4533.         /// <summary>Update the caret color</summary>
  4534.         public void SetCaretColor(ColorValue color) { caretColor = color; }
  4535.  
  4536.         /// <summary>Get or sets the text</summary>
  4537.         public string Text { get { return textData.Text; } set { SetText(value, false); } }
  4538.         /// <summary>Gets a copy of the text</summary>
  4539.         public string GetCopyText() { return textData.Text.Clone() as string; }
  4540.         #endregion
  4541.  
  4542.         /// <summary>Creates a new edit box control</summary>
  4543.         public EditBox(Dialog parent) : base(parent)
  4544.         {
  4545.             controlType = ControlType.EditBox;
  4546.             parentDialog = parent;
  4547.  
  4548.             border = 5; // Default border
  4549.             spacing = 4; // default spacing
  4550.             isCaretOn = true;
  4551.  
  4552.             textData = new System.Windows.Forms.RichTextBox();
  4553.             // Create the control
  4554.             textData.Visible = true;
  4555.             textData.Font = new System.Drawing.Font("Arial", 8.0f);
  4556.             textData.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
  4557.             textData.Multiline = false;
  4558.             textData.Text = string.Empty;
  4559.             textData.MaxLength = ushort.MaxValue; // 65k characters should be plenty
  4560.             textData.WordWrap = false;
  4561.             // Now create the control
  4562.             textData.CreateControl();
  4563.  
  4564.             isHidingCaret = false;
  4565.             firstVisible = 0;
  4566.             blinkTime = NativeMethods.GetCaretBlinkTime() * 0.001f;
  4567.             lastBlink = FrameworkTimer.GetAbsoluteTime();
  4568.             textColor = new ColorValue(0.06f, 0.06f, 0.06f, 1.0f);
  4569.             selectedTextColor = new ColorValue(1.0f, 1.0f, 1.0f, 1.0f);
  4570.             selectedBackColor = new ColorValue(0.15f, 0.196f, 0.36f, 1.0f);
  4571.             caretColor = new ColorValue(0, 0, 0, 1.0f);
  4572.             caretPosition = textData.SelectionStart = 0;
  4573.             isInsertMode = true;
  4574.             isMouseDragging = false;
  4575.         }
  4576.  
  4577.         /// <summary>Set the caret to a character position, and adjust the scrolling if necessary</summary>
  4578.         protected void PlaceCaret(int pos)
  4579.         {
  4580.             // Store caret position
  4581.             caretPosition = pos;
  4582.  
  4583.             // First find the first visible char
  4584.             for (int i = 0; i < textData.Text.Length; i++)
  4585.             {
  4586.                 System.Drawing.Point p = textData.GetPositionFromCharIndex(i);
  4587.                 if (p.X >= 0) 
  4588.                 {
  4589.                     firstVisible = i; // This is the first visible character
  4590.                     break;
  4591.                 }
  4592.             }
  4593.  
  4594.             // if the new position is smaller than the first visible char 
  4595.             // we'll need to scroll
  4596.             if (firstVisible > caretPosition)
  4597.                 firstVisible = caretPosition;
  4598.         }
  4599.  
  4600.         /// <summary>Clears the edit box</summary>
  4601.         public void Clear()
  4602.         {
  4603.             textData.Text = string.Empty;
  4604.             PlaceCaret(0);
  4605.             textData.SelectionStart = 0;
  4606.         }
  4607.         /// <summary>Sets the text for the control</summary>
  4608.         public void SetText(string text, bool selected)
  4609.         {
  4610.             if (text == null)
  4611.                 text = string.Empty;
  4612.  
  4613.             textData.Text = text;
  4614.             textData.SelectionStart = text.Length;
  4615.             // Move the care to the end of the text
  4616.             PlaceCaret(text.Length);
  4617.             textData.SelectionStart = (selected) ? 0 : caretPosition;
  4618.             FocusText();
  4619.         }
  4620.         /// <summary>Deletes the text that is currently selected</summary>
  4621.         protected void DeleteSelectionText()
  4622.         {
  4623.             int first = Math.Min(caretPosition, textData.SelectionStart);
  4624.             int last = Math.Max(caretPosition, textData.SelectionStart);
  4625.             // Update caret and selection
  4626.             PlaceCaret(first);
  4627.             // Remove the characters
  4628.             textData.Text = textData.Text.Remove(first, (last-first));
  4629.             textData.SelectionStart = caretPosition;
  4630.             FocusText();
  4631.         }
  4632.         /// <summary>Updates the rectangles used by the control</summary>
  4633.         protected override void UpdateRectangles()
  4634.         {
  4635.             // Get the bounding box first
  4636.             base.UpdateRectangles ();
  4637.  
  4638.             // Update text rect
  4639.             textRect = boundingBox;
  4640.             // First inflate by border to compute render rects
  4641.             textRect.Inflate(-border, -border);
  4642.             
  4643.             // Update the render rectangles
  4644.             elementRects[0] = textRect;
  4645.             elementRects[1] = new System.Drawing.Rectangle(boundingBox.Left, boundingBox.Top, (textRect.Left - boundingBox.Left), (textRect.Top - boundingBox.Top));
  4646.             elementRects[2] = new System.Drawing.Rectangle(textRect.Left, boundingBox.Top, textRect.Width, (textRect.Top - boundingBox.Top));
  4647.             elementRects[3] = new System.Drawing.Rectangle(textRect.Right, boundingBox.Top, (boundingBox.Right - textRect.Right), (textRect.Top - boundingBox.Top));
  4648.             elementRects[4] = new System.Drawing.Rectangle(boundingBox.Left, textRect.Top, (textRect.Left - boundingBox.Left), textRect.Height);
  4649.             elementRects[5] = new System.Drawing.Rectangle(textRect.Right, textRect.Top, (boundingBox.Right - textRect.Right), textRect.Height);
  4650.             elementRects[6] = new System.Drawing.Rectangle(boundingBox.Left, textRect.Bottom, (textRect.Left - boundingBox.Left), (boundingBox.Bottom - textRect.Bottom));
  4651.             elementRects[7] = new System.Drawing.Rectangle(textRect.Left, textRect.Bottom, textRect.Width, (boundingBox.Bottom - textRect.Bottom));
  4652.             elementRects[8] = new System.Drawing.Rectangle(textRect.Right, textRect.Bottom, (boundingBox.Right - textRect.Right), (boundingBox.Bottom - textRect.Bottom));            
  4653.  
  4654.             // Inflate further by spacing
  4655.             textRect.Inflate(-spacing, -spacing);
  4656.  
  4657.             // Make the underlying rich text box the same size
  4658.             textData.Size = textRect.Size;
  4659.         }
  4660.  
  4661.         /// <summary>Copy the selected text to the clipboard</summary>
  4662.         protected void CopyToClipboard()
  4663.         {
  4664.             // Copy the selection text to the clipboard
  4665.             if (caretPosition != textData.SelectionStart)
  4666.             {
  4667.                 int first = Math.Min(caretPosition, textData.SelectionStart);
  4668.                 int last = Math.Max(caretPosition, textData.SelectionStart);
  4669.                 // Set the text to the clipboard
  4670.                 System.Windows.Forms.Clipboard.SetDataObject(textData.Text.Substring(first, (last-first)));
  4671.             }
  4672.  
  4673.         }
  4674.         /// <summary>Paste the clipboard data to the control</summary>
  4675.         protected void PasteFromClipboard()
  4676.         {
  4677.             // Get the clipboard data
  4678.             System.Windows.Forms.IDataObject clipData = System.Windows.Forms.Clipboard.GetDataObject();
  4679.             // Does the clipboard have string data?
  4680.             if (clipData.GetDataPresent(System.Windows.Forms.DataFormats.StringFormat))
  4681.             {
  4682.                 // Yes, get that data
  4683.                 string clipString = clipData.GetData(System.Windows.Forms.DataFormats.StringFormat) as string;
  4684.                 // find any new lines, remove everything after that
  4685.                 int index;
  4686.                 if ((index = clipString.IndexOf("\n")) > 0)
  4687.                 {
  4688.                     clipString = clipString.Substring(0, index-1);
  4689.                 }
  4690.  
  4691.                 // Insert that into the text data
  4692.                 textData.Text = textData.Text.Insert(caretPosition, clipString);
  4693.                 caretPosition += clipString.Length;
  4694.                 textData.SelectionStart = caretPosition;
  4695.                 FocusText();
  4696.             }
  4697.         }
  4698.         /// <summary>Reset's the caret blink time</summary>
  4699.         protected void ResetCaretBlink()
  4700.         {
  4701.             isCaretOn = true;
  4702.             lastBlink = FrameworkTimer.GetAbsoluteTime();
  4703.         }
  4704.  
  4705.         /// <summary>Update the caret when focus is in</summary>
  4706.         public override void OnFocusIn()
  4707.         {
  4708.             base.OnFocusIn();
  4709.             ResetCaretBlink();
  4710.         }
  4711.  
  4712.         /// <summary>Updates focus to the backing rich textbox so it updates it's state</summary>
  4713.         private void FocusText()
  4714.         {
  4715.             // Because of a design issue with the rich text box control that is used as 
  4716.             // the backing store for this control, the 'scrolling' mechanism built into
  4717.             // the control will only work if the control has focus.  Setting focus to the 
  4718.             // control here would work, but would cause a bad 'flicker' of the application.
  4719.  
  4720.             // Therefore, the automatic horizontal scrolling is turned off by default.  To 
  4721.             // enable it turn this define on.
  4722. #if (SCROLL_CORRECTLY)
  4723.             NativeMethods.SetFocus(textData.Handle);
  4724.             NativeMethods.SetFocus(Parent.SampleFramework.Window);
  4725. #endif
  4726.         }
  4727.  
  4728.         /// <summary>Handle keyboard input to the edit box</summary>
  4729.         public override bool HandleKeyboard(Microsoft.Samples.DirectX.UtilityToolkit.NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  4730.         {
  4731.             if (!IsEnabled || !IsVisible)
  4732.                 return false;
  4733.  
  4734.             // Default to not handling the message
  4735.             bool isHandled = false;
  4736.             if (msg == NativeMethods.WindowMessage.KeyDown)
  4737.             {
  4738.                 switch((System.Windows.Forms.Keys)wParam.ToInt32())
  4739.                 {
  4740.                     case System.Windows.Forms.Keys.End:
  4741.                     case System.Windows.Forms.Keys.Home:
  4742.                         // Move the caret
  4743.                         if (wParam.ToInt32() == (int)System.Windows.Forms.Keys.End)
  4744.                             PlaceCaret(textData.Text.Length);
  4745.                         else
  4746.                             PlaceCaret(0);
  4747.                         if (!NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
  4748.                         {
  4749.                             // Shift is not down. Update selection start along with caret
  4750.                             textData.SelectionStart = caretPosition;
  4751.                             FocusText();
  4752.                         }
  4753.  
  4754.                         ResetCaretBlink();
  4755.                         isHandled = true;
  4756.                         break;
  4757.                     case System.Windows.Forms.Keys.Insert:
  4758.                         if (NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ControlKey))
  4759.                         {
  4760.                             // Control insert -> Copy to clipboard
  4761.                             CopyToClipboard();
  4762.                         }
  4763.                         else if (NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
  4764.                         {
  4765.                             // Shift insert -> Paste from clipboard
  4766.                             PasteFromClipboard();
  4767.                         }
  4768.                         else
  4769.                         {
  4770.                             // Toggle insert mode
  4771.                             isInsertMode = !isInsertMode;
  4772.                         }
  4773.                         break;
  4774.                     case System.Windows.Forms.Keys.Delete:
  4775.                         // Check to see if there is a text selection
  4776.                         if (caretPosition != textData.SelectionStart)
  4777.                         {
  4778.                             DeleteSelectionText();
  4779.                             RaiseChangedEvent(this, true);
  4780.                         }
  4781.                         else
  4782.                         {
  4783.                             if (caretPosition < textData.Text.Length)
  4784.                             {
  4785.                                 // Deleting one character
  4786.                                 textData.Text = textData.Text.Remove(caretPosition, 1);
  4787.                                 RaiseChangedEvent(this, true);
  4788.                             }
  4789.                         }
  4790.                         ResetCaretBlink();
  4791.                         isHandled = true;
  4792.                         break;
  4793.  
  4794.                     case System.Windows.Forms.Keys.Left:
  4795.                         if (NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ControlKey))
  4796.                         {
  4797.                             // Control is down. Move the caret to a new item
  4798.                             // instead of a character.
  4799.                         }
  4800.                         else if (caretPosition > 0)
  4801.                             PlaceCaret(caretPosition - 1); // Move one to the left
  4802.  
  4803.                         if (!NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
  4804.                         {
  4805.                             // Shift is not down. Update selection
  4806.                             // start along with the caret.
  4807.                             textData.SelectionStart = caretPosition;
  4808.                             FocusText();
  4809.                         }
  4810.                         ResetCaretBlink();
  4811.                         isHandled = true;
  4812.                         break;
  4813.  
  4814.                     case System.Windows.Forms.Keys.Right:
  4815.                         if (NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ControlKey))
  4816.                         {
  4817.                             // Control is down. Move the caret to a new item
  4818.                             // instead of a character.
  4819.                         }
  4820.                         else if (caretPosition < textData.Text.Length)
  4821.                             PlaceCaret(caretPosition + 1); // Move one to the left
  4822.                         if (!NativeMethods.IsKeyDown(System.Windows.Forms.Keys.ShiftKey))
  4823.                         {
  4824.                             // Shift is not down. Update selection
  4825.                             // start along with the caret.
  4826.                             textData.SelectionStart = caretPosition;
  4827.                             FocusText();
  4828.                         }
  4829.                         ResetCaretBlink();
  4830.                         isHandled = true;
  4831.                         break;
  4832.  
  4833.                     case System.Windows.Forms.Keys.Up:
  4834.                     case System.Windows.Forms.Keys.Down:
  4835.                         // Trap up and down arrows so that the dialog
  4836.                         // does not switch focus to another control.
  4837.                         isHandled = true;
  4838.                         break;
  4839.  
  4840.                     default:
  4841.                         // Let the application handle escape
  4842.                         isHandled = ((System.Windows.Forms.Keys)wParam.ToInt32()) == System.Windows.Forms.Keys.Escape;
  4843.                         break;
  4844.                 }
  4845.             }
  4846.  
  4847.             return isHandled;
  4848.         }
  4849.  
  4850.         /// <summary>Handle mouse messages</summary>
  4851.         public override bool HandleMouse(NativeMethods.WindowMessage msg, System.Drawing.Point pt, IntPtr wParam, IntPtr lParam)
  4852.         {
  4853.             if (!IsEnabled || !IsVisible)
  4854.                 return false;
  4855.  
  4856.             // We need a new point
  4857.             System.Drawing.Point p = pt;
  4858.             p.X -= textRect.Left;
  4859.             p.Y -= textRect.Top;
  4860.  
  4861.             switch(msg)
  4862.             {
  4863.                 case NativeMethods.WindowMessage.LeftButtonDown:
  4864.                 case NativeMethods.WindowMessage.LeftButtonDoubleClick:
  4865.                     // Get focus first
  4866.                     if (!hasFocus)
  4867.                         Dialog.RequestFocus(this);
  4868.  
  4869.                     if (!ContainsPoint(pt))
  4870.                         return false;
  4871.  
  4872.                     isMouseDragging = true;
  4873.                     NativeMethods.SetCapture(Parent.SampleFramework.Window);
  4874.                     // Determine the character corresponding to the coordinates
  4875.                     int index = textData.GetCharIndexFromPosition(p);
  4876.  
  4877.                     if (index < textData.Text.Length)
  4878.                         PlaceCaret(index + 1);
  4879.                     else
  4880.                         PlaceCaret(index);
  4881.                     
  4882.                     textData.SelectionStart = caretPosition;
  4883.                     FocusText();
  4884.                     ResetCaretBlink();
  4885.                     return true;
  4886.  
  4887.                 case NativeMethods.WindowMessage.LeftButtonUp:
  4888.                     NativeMethods.ReleaseCapture();
  4889.                     isMouseDragging = false;
  4890.                     break;
  4891.                 case NativeMethods.WindowMessage.MouseMove:
  4892.                     if (isMouseDragging)
  4893.                     {
  4894.                         // Determine the character corresponding to the coordinates
  4895.                         int dragIndex = textData.GetCharIndexFromPosition(p);
  4896.  
  4897.                         if (dragIndex < textData.Text.Length)
  4898.                             PlaceCaret(dragIndex + 1);
  4899.                         else
  4900.                             PlaceCaret(dragIndex);
  4901.                     }
  4902.                     break;
  4903.             }
  4904.             return false;
  4905.         }
  4906.  
  4907.         /// <summary>Handle all other messages</summary>
  4908.         public override bool MsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam)
  4909.         {
  4910.             if (!IsEnabled || !IsVisible)
  4911.                 return false;
  4912.  
  4913.             if (msg == NativeMethods.WindowMessage.Character)
  4914.             {
  4915.                 int charKey = wParam.ToInt32();
  4916.                 switch(charKey)
  4917.                 {
  4918.                     case (int)System.Windows.Forms.Keys.Back:
  4919.                     {
  4920.                         // If there's a selection, treat this
  4921.                         // like a delete key.
  4922.                         if (caretPosition != textData.SelectionStart)
  4923.                         {
  4924.                             DeleteSelectionText();
  4925.                             RaiseChangedEvent(this, true);
  4926.                         }
  4927.                         else if (caretPosition > 0)
  4928.                         {
  4929.                             // Move the caret and delete the char
  4930.                             textData.Text = textData.Text.Remove(caretPosition - 1, 1);
  4931.                             PlaceCaret(caretPosition - 1);
  4932.                             textData.SelectionStart = caretPosition;
  4933.                             FocusText();
  4934.                             RaiseChangedEvent(this, true);
  4935.                         }
  4936.  
  4937.                         ResetCaretBlink();
  4938.                         break;
  4939.                     }
  4940.                     case 24: // Ctrl-X Cut
  4941.                     case (int)System.Windows.Forms.Keys.Cancel: // Ctrl-C Copy
  4942.                     {
  4943.                         CopyToClipboard();
  4944.  
  4945.                         // If the key is Ctrl-X, delete the selection too.
  4946.                         if (charKey == 24)
  4947.                         {
  4948.                             DeleteSelectionText();
  4949.                             RaiseChangedEvent(this, true);
  4950.                         }
  4951.  
  4952.                         break;
  4953.                     }
  4954.  
  4955.                     // Ctrl-V Paste
  4956.                     case 22:
  4957.                     {
  4958.                         PasteFromClipboard();
  4959.                         RaiseChangedEvent(this, true);
  4960.                         break;
  4961.                     }
  4962.                     case (int)System.Windows.Forms.Keys.Return:
  4963.                         // Invoke the event when the user presses Enter.
  4964.                         RaiseEnterEvent(this, true);
  4965.                         break;
  4966.  
  4967.                     // Ctrl-A Select All
  4968.                     case 1:
  4969.                     {
  4970.                         if (textData.SelectionStart == caretPosition)
  4971.                         {
  4972.                             textData.SelectionStart = 0;
  4973.                             PlaceCaret(textData.Text.Length);
  4974.                         }
  4975.                         break;
  4976.                     }
  4977.  
  4978.                     // Junk characters we don't want in the string
  4979.                     case 26:  // Ctrl Z
  4980.                     case 2:   // Ctrl B
  4981.                     case 14:  // Ctrl N
  4982.                     case 19:  // Ctrl S
  4983.                     case 4:   // Ctrl D
  4984.                     case 6:   // Ctrl F
  4985.                     case 7:   // Ctrl G
  4986.                     case 10:  // Ctrl J
  4987.                     case 11:  // Ctrl K
  4988.                     case 12:  // Ctrl L
  4989.                     case 17:  // Ctrl Q
  4990.                     case 23:  // Ctrl W
  4991.                     case 5:   // Ctrl E
  4992.                     case 18:  // Ctrl R
  4993.                     case 20:  // Ctrl T
  4994.                     case 25:  // Ctrl Y
  4995.                     case 21:  // Ctrl U
  4996.                     case 9:   // Ctrl I
  4997.                     case 15:  // Ctrl O
  4998.                     case 16:  // Ctrl P
  4999.                     case 27:  // Ctrl [
  5000.                     case 29:  // Ctrl ]
  5001.                     case 28:  // Ctrl \ 
  5002.                         break;
  5003.                     
  5004.                     default:
  5005.                     {
  5006.                         // If there's a selection and the user
  5007.                         // starts to type, the selection should
  5008.                         // be deleted.
  5009.                         if (caretPosition != textData.SelectionStart)
  5010.                         {
  5011.                             DeleteSelectionText();
  5012.                         }
  5013.                         // If we are in overwrite mode and there is already
  5014.                         // a char at the caret's position, simply replace it.
  5015.                         // Otherwise, we insert the char as normal.
  5016.                         if (!isInsertMode && caretPosition < textData.Text.Length)
  5017.                         {
  5018.                             // This isn't the most efficient way to do this, but it's simple
  5019.                             // and shows the correct behavior
  5020.                             char[] charData = textData.Text.ToCharArray();
  5021.                             charData[caretPosition] = (char)wParam.ToInt32();
  5022.                             textData.Text = new string(charData);
  5023.                         }
  5024.                         else
  5025.                         {
  5026.                             // Insert the char
  5027.                             char c = (char)wParam.ToInt32();
  5028.                             textData.Text = textData.Text.Insert(caretPosition, c.ToString());
  5029.                         }
  5030.  
  5031.                         // Move the caret and selection position now
  5032.                         PlaceCaret(caretPosition + 1);
  5033.                         textData.SelectionStart = caretPosition;
  5034.                         FocusText();
  5035.  
  5036.                         ResetCaretBlink();
  5037.                         RaiseChangedEvent(this, true);
  5038.                         break;
  5039.                     }
  5040.                 }
  5041.             }
  5042.             return false;
  5043.         }
  5044.  
  5045.  
  5046.         /// <summary>Render the control</summary>
  5047.         public override void Render(Device device, float elapsedTime)
  5048.         {
  5049.             if (!IsVisible)
  5050.                 return; // Nothing to render
  5051.  
  5052.             // Render the control graphics
  5053.             for (int i = 0; i <= LowerRightBorder; ++i)
  5054.             {
  5055.                 Element e = elementList[i] as Element;
  5056.                 e.TextureColor.Blend(ControlState.Normal,elapsedTime);
  5057.                 parentDialog.DrawSprite(e, elementRects[i]);
  5058.             }
  5059.             //
  5060.             // Compute the X coordinates of the first visible character.
  5061.             //
  5062.             int xFirst = textData.GetPositionFromCharIndex(firstVisible).X;
  5063.             int xCaret = textData.GetPositionFromCharIndex(caretPosition).X;
  5064.             int xSel;
  5065.  
  5066.             if (caretPosition != textData.SelectionStart)
  5067.                 xSel = textData.GetPositionFromCharIndex(textData.SelectionStart).X;
  5068.             else
  5069.                 xSel = xCaret;
  5070.  
  5071.             // Render the selection rectangle
  5072.             System.Drawing.Rectangle selRect = System.Drawing.Rectangle.Empty;
  5073.             if (caretPosition != textData.SelectionStart)
  5074.             {
  5075.                 int selLeft = xCaret, selRight = xSel;
  5076.                 // Swap if left is beigger than right
  5077.                 if (selLeft > selRight)
  5078.                 {
  5079.                     int temp = selLeft;
  5080.                     selLeft = selRight;
  5081.                     selRight = temp;
  5082.                 }
  5083.                 selRect = System.Drawing.Rectangle.FromLTRB(
  5084.                     selLeft, textRect.Top, selRight, textRect.Bottom);
  5085.                 selRect.Offset(textRect.Left - xFirst, 0);
  5086.                 selRect.Intersect(textRect);
  5087.                 Parent.DrawRectangle(selRect, selectedBackColor);
  5088.             }
  5089.  
  5090.             // Render the text
  5091.             Element textElement = elementList[TextLayer] as Element;
  5092.             textElement.FontColor.Current = textColor;
  5093.             parentDialog.DrawText(textData.Text.Substring(firstVisible), textElement, textRect);
  5094.             
  5095.             // Render the selected text
  5096.             if (caretPosition != textData.SelectionStart)
  5097.             {
  5098.                 int firstToRender = Math.Max(firstVisible, Math.Min(textData.SelectionStart, caretPosition));
  5099.                 int numToRender = Math.Max(textData.SelectionStart, caretPosition) - firstToRender;
  5100.                 textElement.FontColor.Current = selectedTextColor;
  5101.                 parentDialog.DrawText(textData.Text.Substring(firstToRender, numToRender), textElement, selRect);
  5102.             }
  5103.  
  5104.             //
  5105.             // Blink the caret
  5106.             //
  5107.             if(FrameworkTimer.GetAbsoluteTime() - lastBlink >= blinkTime)
  5108.             {
  5109.                 isCaretOn = !isCaretOn;
  5110.                 lastBlink = FrameworkTimer.GetAbsoluteTime();
  5111.             }
  5112.  
  5113.             //
  5114.             // Render the caret if this control has the focus
  5115.             //
  5116.             if( hasFocus && isCaretOn && !isHidingCaret )
  5117.             {
  5118.                 // Start the rectangle with insert mode caret
  5119.                 System.Drawing.Rectangle caretRect = textRect;
  5120.                 caretRect.Width = 2;
  5121.                 caretRect.Location = new System.Drawing.Point(
  5122.                     caretRect.Left - xFirst + xCaret -1, 
  5123.                     caretRect.Top);
  5124.                 
  5125.                 // If we are in overwrite mode, adjust the caret rectangle
  5126.                 // to fill the entire character.
  5127.                 if (!isInsertMode)
  5128.                 {
  5129.                     // Obtain the X coord of the current character
  5130.                     caretRect.Width = 4;
  5131.                 }
  5132.  
  5133.                 parentDialog.DrawRectangle(caretRect, caretColor);
  5134.             }
  5135.  
  5136.         }
  5137.     }
  5138. }