Chad Vernon
  • Home
  • Reel/Resume
  • Work
  • Resources
  • About
  • Contact
Home » Resources » Managed DirectX 2.0 » Creating a GUI (Part 3)
sideBar

Search

Categories

  • CG
  • cvxporter
  • Maya
  • Personal

Archives

  • July 2010
  • May 2010
  • April 2010
  • March 2010
  • December 2009
  • October 2009
  • September 2009
  • August 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007

Rss

  • Main Entries RSS
  • Comments RSS

Creating a GUI (Part 3)

  CU_MDX_GUI.zip (63.8 KiB, 5,845 hits)


  CUnitFramework.zip (101.1 KiB, 15,246 hits)

Extract the C-Unit Framework
inside the project (not solution) directory.

In Part 3 of the GUI series, we will create_ the following more complex controls: ComboBoxes, ListBoxes, and EditBoxes. ListBoxes and Comboxes both hold lists of items that the user can select from. This item will be defined as follows:

/// <summary>ListableItem for Controls that list items.</summary>
public class ListableItem
{

private string m_text;
private object m_data;
private bool m_selected;
private ColorValue m_textColor;

/// <summary>Creates a new ListableItem.</summary>
/// <param name=”text”>Text to display</param>
/// <param name=”data”>Data for item to hold</param>
public ListableItem( string text, object data ) Toggle

{

m_text = text;
m_data = data;

}

/// <summary>Gets the text of the ListableItem</summary>
public string Text Toggle

{

get { return m_text; }

}

/// <summary>Gets and sets whether the ListableItem is selected.</summary>
public bool Selected Toggle

{

get { return m_selected; }
set { m_selected = value; }

}

/// <summary>Gets and sets the text color of the ListableItem</summary>
public ColorValue TextColor Toggle

{

get { return m_textColor; }
set { m_textColor = value; }

}

/// <summary>Gets the data of the ListableItem</summary>
public object Data Toggle

{

get { return m_data; }

}

}

The ListableItem class represents a single item stored in a ComboBox or ListBox. Both of these Controls will have a List of ListableItems that the user will be able to choose from. With ListableItem now out of the way, we can move on to create_ a ListBox.

/// <summary>
/// A ListBox control
/// </summary>
public class ListBox : Control
{

protected List<Quad> m_scrollUp;
protected List<Quad> m_scrollDown;
protected List<Quad> m_scrollMarker;
protected List<Quad> m_disabledQuads;
protected List<Quad> m_highlightQuads;
protected List<Quad> m_normalHighlights;
protected List<Quad> m_disabledHighlights;
protected List<ListableItem> m_items;
protected List<Rectangle> m_hotspots;
protected int m_topItem;
protected float m_itemHeight;
protected float m_minMarkerHeight;
protected int m_numDisplayedItems;
protected int m_highlightColor;
protected int m_disabledHighlightColor;
protected bool m_scrolling;
protected bool m_overState;
protected bool m_singleItemListBox;
protected bool m_newData;

protected enum Section { Left, Right, Top, Bottom, Background, TopLeft, TopRight, BottomLeft, BottomRight, ScrollUp, ScrollDown, ScrollBody, ScrollMarker };
protected enum HotSpot { Background, ScrollUp, ScrollDown, ScrollMarker, ScrollBody };
protected enum Highlight { Normal, Disabled };

/// <summary>Default Constructor</summary>
public ListBox() Toggle

{

// Empty

}

/// <summary>Creates a ListBox</summary>
/// <param name=”id”>Control ID</param>
/// <param name=”singleItemSelect”>Whether single or multiple items can be selected</param>
/// <param name=”screenRect”>Screen rectangle</param>
/// <param name=”fontSize”>Font size</param>
/// <param name=”textColor”>Text color</param>
/// <param name=”font”>Bitmap Font</param>
/// <param name=”node”>ControlNode from XML file</param>
/// <param name=”info”>Texture ImageInformation</param>
public ListBox( int id, bool singleItemSelect, RectangleF screenRect, float fontSize, ColorValue textColor, BitmapFont font, ControlNode node, ImageInformation info ) Toggle

{

m_topItem = 0;
m_id = id;
m_minMarkerHeight = 5f;
m_fontSize = fontSize;
m_itemHeight = 0f;
m_textColor = textColor;
m_bFont = font;
m_scrolling = false;
m_overState = false;
m_newData = false;
m_singleItemListBox = singleItemSelect;
m_position = new PointF( screenRect.X, screenRect.Y );
m_size = new SizeF( screenRect.Width, screenRect.Height );
m_data = new ArrayList();

int index = m_bFont.AddString( “x”, new RectangleF( 0f, 0f, 0f, 0f ), BitmapFont.Align.Left, m_fontSize, m_textColor, true );
m_itemHeight = m_bFont.GetLineHeight( index );
m_bFont.ClearString( index );

m_scrollUp = new List<Quad>();
m_scrollDown = new List<Quad>();
m_scrollMarker = new List<Quad>();
m_quads = new List<Quad>();
m_disabledQuads = new List<Quad>();
m_normalHighlights = new List<Quad>();
m_disabledHighlights = new List<Quad>();
m_highlightQuads = new List<Quad>();
m_items = new List<ListableItem>();
m_hotspots = new List<Rectangle>();

// Initialize Lists so we can access them with indices
m_highlightQuads.Add( new Quad() );
m_highlightQuads.Add( new Quad() );
for ( int i = 0; i < 5; i++ )
{

m_hotspots.Add( new Rectangle() );

}
for ( int i = 0; i < 4; i++ )
{

m_scrollUp.Add( new Quad() );
m_scrollDown.Add( new Quad() );
m_scrollMarker.Add( new Quad() );

}
for ( int i = 0; i < 13; i++ )
{

m_quads.Add( new Quad() );
m_disabledQuads.Add( new Quad() );

}

float z = 0f;
float rhw = 1f;
foreach ( ImageNode i in node.Images )
{

RectangleF rect = i.Rectangle;

TransformedColoredTextured topLeft = new TransformedColoredTextured(
screenRect.X, screenRect.Y, z, rhw,
i.Color, rect.X / (float)info.Width, rect.Y / (float)info.Height );
TransformedColoredTextured topRight = new TransformedColoredTextured(
screenRect.X + rect.Width, screenRect.Y, z, rhw,
i.Color, rect.Right / (float)info.Width, rect.Y / (float)info.Height );
TransformedColoredTextured bottomRight = new TransformedColoredTextured(
screenRect.X + rect.Width, screenRect.Y + rect.Height, z, rhw,
i.Color, rect.Right / (float)info.Width, rect.Bottom / (float)info.Height );
TransformedColoredTextured bottomLeft = new TransformedColoredTextured(
screenRect.X, screenRect.Y + rect.Height, z, rhw,
i.Color, rect.X / (float)info.Width, rect.Bottom / (float)info.Height );
Quad q = new Quad( topLeft, topRight, bottomLeft, bottomRight );
if ( i.Name.EndsWith( “TopLeftCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.TopLeft] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.TopLeft] = q;

}

}
else if ( i.Name.EndsWith( “TopBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Top] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Top] = q;

}

}
else if ( i.Name.EndsWith( “TopRightCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.TopRight] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.TopRight] = q;

}

}
else if ( i.Name.EndsWith( “LeftBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Left] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Left] = q;

}

}
else if ( i.Name.EndsWith( “Background” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Background] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Background] = q;

}

}
else if ( i.Name.EndsWith( “RightBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Right] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Right] = q;

}

}
else if ( i.Name.EndsWith( “BottomLeftCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.BottomLeft] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.BottomLeft] = q;

}

}
else if ( i.Name.EndsWith( “BottomBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Bottom] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Bottom] = q;

}

}
else if ( i.Name.EndsWith( “BottomRightCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.BottomRight] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.BottomRight] = q;

}

}
else if ( i.Name.EndsWith( “ScrollBody” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.ScrollBody] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.ScrollBody] = q;

}

}
else if ( i.Name.EndsWith( “Highlight” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

q.Height = m_fontSize + 6f;
m_highlightQuads[(int)Highlight.Normal] = q;
m_highlightColor = i.Color.ToArgb();

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledHighlightColor = i.Color.ToArgb();
m_highlightQuads[(int)Highlight.Disabled] = q;

}

}
else if ( i.Name.EndsWith( “ScrollUp” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.ScrollUp] = q;
m_scrollUp[(int)ControlState.Normal] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_scrollUp[(int)ControlState.Over] = q;

}
else if ( i.Name.StartsWith( “Down” ) )
{

m_scrollUp[(int)ControlState.Down] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_scrollUp[(int)ControlState.Disabled] = q;
m_disabledQuads[(int)Section.ScrollUp] = q;

}

}
else if ( i.Name.EndsWith( “ScrollDown” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.ScrollDown] = q;
m_scrollDown[(int)ControlState.Normal] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_scrollDown[(int)ControlState.Over] = q;

}
else if ( i.Name.StartsWith( “Down” ) )
{

m_scrollDown[(int)ControlState.Down] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_scrollDown[(int)ControlState.Disabled] = q;
m_disabledQuads[(int)Section.ScrollDown] = q;

}

}
else if ( i.Name.EndsWith( “ScrollMarker” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.ScrollMarker] = q;
m_scrollMarker[(int)ControlState.Normal] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_scrollMarker[(int)ControlState.Over] = q;

}
else if ( i.Name.StartsWith( “Down” ) )
{

m_scrollMarker[(int)ControlState.Down] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.ScrollMarker] = q;
m_scrollMarker[(int)ControlState.Disabled] = q;

}

}

}

PositionQuads();

}

/// <summary>Adds a new item to the ListBox.</summary>
/// <param name=”text”>Item text.</param>
/// <param name=”data”>Item data.</param>
public virtual void AddItem( string text, object data ) Toggle

{

m_items.Add( new ListableItem( text, data ) );
BuildText();

// Highlights are designated by item index
Quad normalHighlight = (Quad)m_highlightQuads[(int)Highlight.Normal].Clone();
normalHighlight.X = m_quads[(int)Section.Background].X;
normalHighlight.Width = m_quads[(int)Section.Background].Width;
normalHighlight.Color = 0;
m_normalHighlights.Add( normalHighlight );
m_quads.Add( normalHighlight );

Quad disabledHighlight = (Quad)m_highlightQuads[(int)Highlight.Disabled].Clone();
disabledHighlight.X = m_quads[(int)Section.Background].X;
disabledHighlight.Width = m_quads[(int)Section.Background].Width;
disabledHighlight.Color = 0;
m_disabledHighlights.Add( disabledHighlight );
m_disabledQuads.Add( disabledHighlight );

for ( int i = 0; i < 4; i++ )
{

if ( m_numDisplayedItems == m_items.Count )
{

m_scrollMarker[i].Height = 0f;

}
else
{

m_scrollMarker[i].Height = m_quads[(int)Section.ScrollBody].Height / ( (float)m_items.Count – (float)m_numDisplayedItems + 1 );
m_scrollMarker[i].Height = Math.Max( m_scrollMarker[i].Height, m_minMarkerHeight );

}

}
m_numDisplayedItems = (int)( m_quads[(int)Section.Background].Height / m_itemHeight );
m_numDisplayedItems = Math.Min( m_numDisplayedItems, m_items.Count );
BuildText();
BuildHotspots();

}

/// <summary>Checks is the mouse is over the Control’s hotspot</summary>
/// <param name=”cursor”>Mouse position</param>
/// <returns>true if the cursor is over the Control’s hotspot, false otherwise.</returns>
public override bool Contains( Point cursor ) Toggle

{

foreach ( Rectangle r in m_hotspots )
{

if ( r.Contains( cursor ) )
{

return true;

}

}
if ( m_overState )
{

m_overState = false;
m_quads[(int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Normal];
m_quads[(int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Normal];
m_quads[(int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Normal];

}
return false;

}

/// <summary>Mouse Over event</summary>
/// <param name=”cursor”>Mouse position</param>
/// <param name=”buttons”>Mouse buttons</param>
protected override void OnMouseOver( Point cursor, bool[] buttons ) Toggle

{

if ( m_hotspots[(int)HotSpot.ScrollUp].Contains( cursor ) )
{

m_overState = true;
m_quads[(int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Over];

}
else
{

m_quads[(int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Normal];

}
if ( m_hotspots[(int)HotSpot.ScrollDown].Contains( cursor ) )
{

m_overState = true;
m_quads[(int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Over];

}
else
{

m_quads[(int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Normal];

}
if ( m_hotspots[(int)HotSpot.ScrollMarker].Contains( cursor ) )
{

m_overState = true;
m_quads[(int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Over];

}
else
{

m_quads[(int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Normal];

}

}

/// <summary>Mouse Down event</summary>
/// <param name=”cursor”>Mouse position</param>
/// <param name=”buttons”>Mouse buttons</param>
protected override void OnMouseDown( Point cursor, bool[] buttons ) Toggle

{

if ( m_hotspots[(int)HotSpot.ScrollUp].Contains( cursor ) && !m_hasFocus )
{

m_quads[(int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Down];

}
else if ( !m_hasFocus )
{

m_quads[(int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Normal];

}
if ( m_hotspots[(int)HotSpot.ScrollDown].Contains( cursor ) && !m_hasFocus )
{

m_quads[(int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Down];

}
else if ( !m_hasFocus )
{

m_quads[(int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Normal];

}
if ( m_hotspots[(int)HotSpot.ScrollMarker].Contains( cursor ) && !m_hasFocus )
{

m_quads[(int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Down];

}
else if ( !m_hasFocus )
{

m_quads[(int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Normal];

}
if ( ( m_hotspots[(int)HotSpot.ScrollBody].Contains( cursor ) || m_scrolling ) &&
cursor.Y < m_quads[(int)Section.ScrollBody].Bottom &&
cursor.Y > m_quads[(int)Section.ScrollBody].Y )
{

// Scroll with draggable scroll box
m_scrolling = true;
m_quads[(int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Down];

// Move scroll marker
for ( int i = 0; i < 4; i++ )
{

m_scrollMarker[i].Y =
m_scrollMarker[i].Y = cursor.Y – ( m_scrollMarker[i].Height / 2f );
m_scrollMarker[i].Y = Math.Max( m_scrollMarker[i].Y,
m_quads[(int)Section.ScrollBody].Y );
m_scrollMarker[i].Y = Math.Min( m_scrollMarker[i].Y,
m_quads[(int)Section.ScrollDown].Y – m_scrollMarker[i].Height );

}
m_disabledQuads[(int)Section.ScrollMarker].Y = m_quads[(int)Section.ScrollMarker].Y;

// Change item range

int oldTopItem = m_topItem;
int divisionHeight = (int)m_quads[(int)Section.ScrollBody].Height / ( m_items.Count – m_numDisplayedItems + 1 );
if ( divisionHeight > 0 )
{

m_topItem = ( cursor.Y – (int)m_quads[(int)Section.ScrollBody].Y ) / divisionHeight;
m_topItem = Math.Min( m_topItem, m_items.Count – m_numDisplayedItems );

}
else
{

m_topItem = 0;

}

// Scroll highlights also
float highlightOffset = (float)( oldTopItem – m_topItem ) * m_itemHeight;
for ( int i = 0; i < m_normalHighlights.Count; i++ )
{

m_normalHighlights[i].Y += highlightOffset;
m_disabledHighlights[i].Y += highlightOffset;
if ( m_normalHighlights[i].Y < m_quads[(int)Section.Background].Y ||
m_normalHighlights[i].Bottom > m_quads[(int)Section.Background].Bottom )
{

m_normalHighlights[i].Color = 0;
m_disabledHighlights[i].Color = 0;

}
else if ( m_items[i].Selected )
{

m_normalHighlights[i].Color = m_highlightColor;
m_disabledHighlights[i].Color = m_disabledHighlightColor;

}

}

// Update the text and hotspots
BuildText();
BuildHotspots();

}

}

/// <summary>Mouse Release event</summary>
/// <param name=”cursor”>Mouse position</param>
protected override void OnMouseRelease( Point cursor ) Toggle

{

m_scrolling = false;
m_newData = false;
if ( m_hotspots[(int)HotSpot.ScrollDown].Contains( cursor ) )
{

ScrollDown();
BuildHotspots();

}
else if ( m_hotspots[(int)HotSpot.ScrollUp].Contains( cursor ) )
{

ScrollUp();

}
else if ( m_hotspots[(int)HotSpot.Background].Contains( cursor ) )
{

int highlightedItem = ( cursor.Y – (int)m_quads[(int)Section.Background].Y ) / (int)m_itemHeight;
if ( ( highlightedItem < m_numDisplayedItems ) && ( highlightedItem + m_topItem < m_items.Count ) )
{

highlightedItem += m_topItem;
m_items[highlightedItem].Selected = !m_items[highlightedItem].Selected;
if ( m_items[highlightedItem].Selected )
{

// Check for new data
m_newData = true;
foreach ( object o in (ArrayList)m_data )
{

if ( m_items[highlightedItem].Data == o )
{

m_newData = false;
break;

}

}

// Turn alpha on
m_normalHighlights[highlightedItem].Color = m_highlightColor;
m_disabledHighlights[highlightedItem].Color = m_disabledHighlightColor;

// Deselect other items if a single item list box
if ( m_singleItemListBox )
{

( (ArrayList)m_data ).Clear();
for ( int i = 0; i < m_items.Count; i++ )
{

if ( i != highlightedItem )
{

m_items[i].Selected = false;
m_normalHighlights[i].Color = 0;
m_disabledHighlights[i].Color = 0;

}

}

}
( (ArrayList)m_data ).Add( m_items[highlightedItem].Data );

float newY = ( highlightedItem – m_topItem ) * m_itemHeight + (int)m_quads[(int)Section.Background].Y;
m_normalHighlights[highlightedItem].Y = newY;
m_disabledHighlights[highlightedItem].Y = newY;
m_normalHighlights[highlightedItem].Color = m_highlightColor;
m_disabledHighlights[highlightedItem].Color = m_disabledHighlightColor;

}
else
{

// Item was deselected
m_newData = true;
( (ArrayList)m_data ).Remove( m_items[highlightedItem].Data );
m_normalHighlights[highlightedItem].Color = 0;
m_disabledHighlights[highlightedItem].Color = 0;

}

}

}
BuildHotspots();

}

/// <summary>Scrolls down one line</summary>
protected virtual void ScrollDown() Toggle

{

if ( m_topItem + m_numDisplayedItems < m_items.Count )
{

m_topItem++;

// Move marker down
int divisionHeight = (int)m_quads[(int)Section.ScrollBody].Height / ( m_items.Count – m_numDisplayedItems + 1 );
for ( int i = 0; i < 4; i++ )
{

m_scrollMarker[i].Y = m_quads[(int)Section.ScrollBody].Y + ( (float)m_topItem * (float)divisionHeight );

}

BuildText();

// Adjust the highlights
for ( int i = 0; i < m_normalHighlights.Count; i++ )
{

m_normalHighlights[i].Y -= m_itemHeight;
m_disabledHighlights[i].Y -= m_itemHeight;

if ( m_normalHighlights[i].Y < m_quads[(int)Section.Background].Y ||
m_normalHighlights[i].Bottom > m_quads[(int)Section.Background].Bottom )
{

m_normalHighlights[i].Color = 0;
m_disabledHighlights[i].Color = 0;

}
else if ( m_items[i].Selected )
{

m_normalHighlights[i].Color = m_highlightColor;
m_disabledHighlights[i].Color = m_disabledHighlightColor;

}

}

}
else
{

for ( int i = 0; i < 4; i++ )
{

m_scrollMarker[i].Y = m_quads[(int)Section.ScrollBody].Bottom – m_quads[(int)Section.ScrollMarker].Height;

}

}

}

/// <summary>Scrolls up one line</summary>
protected virtual void ScrollUp() Toggle

{

if ( m_topItem > 0 )
{

m_topItem–;

// Move marker up
int divisionHeight = (int)m_quads[(int)Section.ScrollBody].Height / ( m_items.Count – m_numDisplayedItems + 1 );
for ( int i = 0; i < 4; i++ )
{

m_scrollMarker[i].Y = m_quads[(int)Section.ScrollBody].Y + ( (float)m_topItem * (float)divisionHeight );

}

BuildText();

// Adjust the highlights
for ( int i = 0; i < m_normalHighlights.Count; i++ )
{

m_normalHighlights[i].Y += m_itemHeight;
m_disabledHighlights[i].Y += m_itemHeight;

if ( m_normalHighlights[i].Y < m_quads[(int)Section.Background].Y ||
m_normalHighlights[i].Bottom > m_quads[(int)Section.Background].Bottom )
{

m_normalHighlights[i].Color = 0;
m_disabledHighlights[i].Color = 0;

}
else if ( m_items[i].Selected )
{

m_normalHighlights[i].Color = m_highlightColor;
m_disabledHighlights[i].Color = m_disabledHighlightColor;

}

}

}
else
{

for ( int i = 0; i < 4; i++ )
{

m_scrollMarker[i].Y = m_quads[(int)Section.ScrollBody].Y;

}

}

}

/// <summary>Mouse wheel event</summary>
/// <param name=”cursor”>Mouse wheel delta</param>
protected override void OnZDelta( float zDelta ) Toggle

{

if ( zDelta > 0f )
{

ScrollUp();

}
else
{

ScrollDown();

}

}

/// <summary>Gets the Button’s current Quads</summary>
public override List<Quad> Quads Toggle

{

get
{

switch ( m_state )
{

case ControlState.Disabled:

return m_disabledQuads;

default:

return m_quads;

}

}

}

/// <summary>Gets and sets the Panel’s position</summary>
public override PointF Position Toggle

{

get { return m_position; }
set
{

float xOffset = value.X – m_position.X;
float yOffset = value.Y – m_position.Y;
m_position = value;
for ( int i = 0; i < m_quads.Count; i++ )
{

if ( i == (int)Section.ScrollUp || i == (int)Section.ScrollDown || i == (int)Section.ScrollMarker )
{

continue;

}
m_quads[i].X += xOffset;
m_quads[i].Y += yOffset;
m_disabledQuads[i].X += xOffset;
m_disabledQuads[i].Y += yOffset;

}
for ( int i = 0; i < 4; i++ )
{

m_scrollUp[i].X += xOffset;
m_scrollUp[i].Y += yOffset;
m_scrollDown[i].X += xOffset;
m_scrollDown[i].Y += yOffset;
m_scrollMarker[i].X += xOffset;
m_scrollMarker[i].Y += yOffset;

}

BuildHotspots();

for ( int i = 0; i < m_fontQuads.Count; i++ )
{

m_fontQuads[i].X += xOffset;
m_fontQuads[i].Y += yOffset;

}

}

}

/// <summary>Positions the Quads</summary>
protected virtual void PositionQuads() Toggle

{

// Adjust middle column x
m_quads[(int)Section.Top].X = m_quads[(int)Section.TopLeft].Right;
m_disabledQuads[(int)Section.Top].X = m_disabledQuads[(int)Section.TopLeft].Right;

m_quads[(int)Section.Background].X = m_quads[(int)Section.Left].Right;
m_disabledQuads[(int)Section.Background].X = m_disabledQuads[(int)Section.Left].Right;

m_quads[(int)Section.Bottom].X = m_quads[(int)Section.BottomLeft].Right;
m_disabledQuads[(int)Section.Bottom].X = m_disabledQuads[(int)Section.BottomLeft].Right;

// Adjust middle column width
m_quads[(int)Section.Top].Width =
m_size.Width – m_quads[(int)Section.TopLeft].Width –
m_quads[(int)Section.TopRight].Width – m_quads[(int)Section.ScrollUp].Width;
m_disabledQuads[(int)Section.Top].Width =
m_size.Width – m_disabledQuads[(int)Section.TopLeft].Width –
m_disabledQuads[(int)Section.TopRight].Width – m_disabledQuads[(int)Section.ScrollUp].Width;

m_quads[(int)Section.Background].Width =
m_size.Width – m_quads[(int)Section.Left].Width –
m_quads[(int)Section.Right].Width – m_quads[(int)Section.ScrollBody].Width;
m_disabledQuads[(int)Section.Background].Width =
m_size.Width – m_disabledQuads[(int)Section.Left].Width –
m_disabledQuads[(int)Section.Right].Width – m_disabledQuads[(int)Section.ScrollBody].Width;

m_quads[(int)Section.Bottom].Width =
m_size.Width – m_quads[(int)Section.BottomLeft].Width –
m_quads[(int)Section.BottomRight].Width – m_quads[(int)Section.ScrollDown].Width;
m_disabledQuads[(int)Section.Bottom].Width =
m_size.Width – m_disabledQuads[(int)Section.BottomLeft].Width –
m_disabledQuads[(int)Section.BottomRight].Width – m_disabledQuads[(int)Section.ScrollDown].Width;

// Adjust right column X
m_quads[(int)Section.TopRight].X =
m_quads[(int)Section.Top].Right;
m_disabledQuads[(int)Section.TopRight].X =
m_disabledQuads[(int)Section.Top].Right;

m_quads[(int)Section.Right].X =
m_quads[(int)Section.Background].Right;
m_disabledQuads[(int)Section.Right].X =
m_disabledQuads[(int)Section.Background].Right;

m_quads[(int)Section.BottomRight].X =
m_quads[(int)Section.Bottom].Right;
m_disabledQuads[(int)Section.BottomRight].X =
m_disabledQuads[(int)Section.Bottom].Right;

// Adjust middle row Y
m_quads[(int)Section.Left].Y = m_quads[(int)Section.TopLeft].Bottom;
m_disabledQuads[(int)Section.Left].Y = m_disabledQuads[(int)Section.TopLeft].Bottom;

m_quads[(int)Section.Background].Y = m_quads[(int)Section.Top].Bottom;
m_disabledQuads[(int)Section.Background].Y = m_disabledQuads[(int)Section.Top].Bottom;

m_quads[(int)Section.Right].Y = m_quads[(int)Section.TopRight].Bottom;
m_disabledQuads[(int)Section.Right].Y = m_disabledQuads[(int)Section.TopRight].Bottom;

// Adjust middle row height
m_quads[(int)Section.Left].Height =
m_size.Height – m_quads[(int)Section.TopLeft].Height –
m_quads[(int)Section.BottomLeft].Height;
m_disabledQuads[(int)Section.Left].Height =
m_size.Height – m_disabledQuads[(int)Section.TopLeft].Height –
m_disabledQuads[(int)Section.BottomLeft].Height;

m_quads[(int)Section.Background].Height =
m_size.Height – m_quads[(int)Section.Top].Height –
m_quads[(int)Section.Bottom].Height;
m_disabledQuads[(int)Section.Background].Height =
m_size.Height – m_disabledQuads[(int)Section.Top].Height –
m_disabledQuads[(int)Section.Bottom].Height;

m_quads[(int)Section.Right].Height =
m_size.Height – m_quads[(int)Section.TopRight].Height –
m_quads[(int)Section.BottomRight].Height;
m_disabledQuads[(int)Section.Right].Height =
m_size.Height – m_disabledQuads[(int)Section.TopRight].Height –
m_disabledQuads[(int)Section.BottomRight].Height;

// Adjust bottom row Y
m_quads[(int)Section.BottomLeft].Y =
m_quads[(int)Section.Left].Bottom;
m_disabledQuads[(int)Section.BottomLeft].Y =
m_disabledQuads[(int)Section.Left].Bottom;

m_quads[(int)Section.Bottom].Y =
m_quads[(int)Section.Background].Bottom;
m_disabledQuads[(int)Section.Bottom].Y =
m_disabledQuads[(int)Section.Background].Bottom;

m_quads[(int)Section.BottomRight].Y =
m_quads[(int)Section.Right].Bottom;
m_disabledQuads[(int)Section.BottomRight].Y =
m_disabledQuads[(int)Section.Right].Bottom;

// Adjust scroll bar X
for ( int i = 0; i < 4; i++ )
{

m_scrollUp[i].X = m_quads[(int)Section.TopRight].Right;
m_scrollDown[i].X = m_quads[(int)Section.BottomRight].Right;
m_scrollMarker[i].X = m_quads[(int)Section.Right].Right;

}

m_quads[(int)Section.ScrollBody].X =
m_quads[(int)Section.Right].Right;
m_disabledQuads[(int)Section.ScrollBody].X =
m_disabledQuads[(int)Section.Right].Right;

// Adjust scroll bar Y
m_quads[(int)Section.ScrollBody].Y =
m_quads[(int)Section.ScrollUp].Bottom;
m_disabledQuads[(int)Section.ScrollBody].Y =
m_disabledQuads[(int)Section.ScrollUp].Bottom;

m_quads[(int)Section.ScrollBody].Height =
m_size.Height – m_quads[(int)Section.ScrollUp].Height –
m_quads[(int)Section.ScrollDown].Height;
m_disabledQuads[(int)Section.ScrollBody].Height =
m_size.Height – m_disabledQuads[(int)Section.ScrollUp].Height –
m_disabledQuads[(int)Section.ScrollDown].Height;

for ( int i = 0; i < 4; i++ )
{

m_scrollDown[i].Y = m_quads[(int)Section.ScrollBody].Bottom;
m_scrollMarker[i].Y = m_quads[(int)Section.ScrollUp].Bottom;

}

BuildHotspots();

BuildText();

}

/// <summary>Builds the hotspots</summary>
protected virtual void BuildHotspots() Toggle

{

m_hotspots[(int)HotSpot.Background] = new Rectangle(
(int)m_quads[(int)Section.Background].X,
(int)m_quads[(int)Section.Background].Y,
(int)m_quads[(int)Section.Background].Width,
(int)m_quads[(int)Section.Background].Height );

m_hotspots[(int)HotSpot.ScrollBody] = new Rectangle(
(int)m_quads[(int)Section.ScrollBody].X,
(int)m_quads[(int)Section.ScrollBody].Y,
(int)m_quads[(int)Section.ScrollBody].Width,
(int)m_quads[(int)Section.ScrollBody].Height );

m_hotspots[(int)HotSpot.ScrollUp] = new Rectangle(
(int)m_quads[(int)Section.ScrollUp].X,
(int)m_quads[(int)Section.ScrollUp].Y,
(int)m_quads[(int)Section.ScrollUp].Width,
(int)m_quads[(int)Section.ScrollUp].Height );

m_hotspots[(int)HotSpot.ScrollDown] = new Rectangle(
(int)m_quads[(int)Section.ScrollDown].X,
(int)m_quads[(int)Section.ScrollDown].Y,
(int)m_quads[(int)Section.ScrollDown].Width,
(int)m_quads[(int)Section.ScrollDown].Height );

m_hotspots[(int)HotSpot.ScrollMarker] = new Rectangle(
(int)m_quads[(int)Section.ScrollMarker].X,
(int)m_quads[(int)Section.ScrollMarker].Y,
(int)m_quads[(int)Section.ScrollMarker].Width,
(int)m_quads[(int)Section.ScrollMarker].Height );

}

/// <summary>Builds the text</summary>
protected virtual new void BuildText() Toggle

{

m_text = “”;
for ( int i = m_topItem; i < m_items.Count; i++ )
{

m_text += m_items[i].Text + “n”;

}
int index = m_bFont.AddString( m_text, new RectangleF(
m_quads[(int)Section.Background].X + 2f, m_quads[(int)Section.Background].Y,
m_quads[(int)Section.Background].Width, m_quads[(int)Section.Background].Height ),
BitmapFont.Align.Left, m_fontSize, m_textColor, true );
List<FontQuad> fontQuads = m_bFont.GetProcessedQuads( index );

m_numDisplayedItems = (int)(m_quads[(int)Section.Background].Height / m_itemHeight);
m_numDisplayedItems = Math.Min( m_numDisplayedItems, m_items.Count );

// Highlight height is dependent on line height
float highlightHeight = m_itemHeight;// +( m_itemHeight / 10f );
for ( int i = 0; i < m_normalHighlights.Count; i++ )
{

m_normalHighlights[i].Height = highlightHeight;
m_disabledHighlights[i].Height = highlightHeight;

}

// Convert FontQuads to Quads
m_fontQuads = new List<Quad>();
for ( int j = 0; j < fontQuads.Count; j++ )
{

m_fontQuads.Add( new Quad( fontQuads[j].TopLeft, fontQuads[j].TopRight, fontQuads[j].BottomLeft, fontQuads[j].BottomRight ) );

}
m_bFont.ClearString( index );

}

/// <summary>Checks if the cursor is in the scrollable background</summary>
/// <param name=”cursor”>Mouse position</param>
/// <returns>true if the cursor is in the scrollable background, false otherwise</returns>
public bool BackgroundContainsCursor( Point cursor ) Toggle

{

return m_hotspots[(int)HotSpot.Background].Contains( cursor );

}

/// <summary>Checks if an item is in the list of items.</summary>
/// <param name=”text”>Item text</param>
/// <returns>true if the item is already in the ListBox, false otherwise.</returns>
public virtual bool ContainsItem( string text ) Toggle

{

for ( int i = 0; i < m_items.Count; i++ )
{

if ( m_items[i].Text == text )
{

return true;

}

}
return false;

}

/// <summary>Clears the ListBox’s current selection</summary>
public virtual void Clear() Toggle

{

if ( m_quads.Count > 13 )
{

m_quads.RemoveRange( 13, m_items.Count );
m_normalHighlights.Clear();
m_disabledHighlights.Clear();

}
( (ArrayList)m_data ).Clear();
m_items.Clear();

}

/// <summary>Selects an item</summary>
/// <param name=”itemText”>Text of item to select</param>
/// <returns>ID of the selected item.</returns>
public virtual int SelectItem( string itemText ) Toggle

{

int id = -1;
if ( m_singleItemListBox )
{

( (ArrayList)m_data ).Clear();

}

for ( int i = 0; i < m_items.Count; i++ )
{

if ( m_items[i].Text != itemText )
{

// Deselect other items if a single item list box
if ( m_singleItemListBox )
{

m_items[i].Selected = false;
m_normalHighlights[i].Color = 0;
m_disabledHighlights[i].Color = 0;

}
continue;

}
id = i;
m_items[i].Selected = true;
( (ArrayList)m_data ).Add( m_items[i].Data );

// Turn alpha on
m_normalHighlights[i].Color = m_highlightColor;
m_disabledHighlights[i].Color = m_disabledHighlightColor;

int oldTopItem = m_topItem;

m_topItem = Math.Min( i, m_items.Count – m_numDisplayedItems );

// Adjust highlights for multiple selection lists
if ( !m_singleItemListBox )
{

float highlightOffset = ( m_topItem – oldTopItem ) * m_itemHeight;
for ( int j = 0; j < m_normalHighlights.Count; j++ )
{

m_normalHighlights[j].Y -= highlightOffset;
m_disabledHighlights[j].Y -= highlightOffset;
if ( m_normalHighlights[j].Y < m_quads[(int)Section.Background].Y ||
m_normalHighlights[j].Bottom > m_quads[(int)Section.Background].Bottom )
{

m_normalHighlights[j].Color = 0;
m_disabledHighlights[j].Color = 0;

}
else if ( m_items[j].Selected )
{

m_normalHighlights[j].Color = m_highlightColor;
m_disabledHighlights[j].Color = m_disabledHighlightColor;

}

}

}

// Move Scroll Marker
int divisionHeight = (int)m_quads[(int)Section.ScrollBody].Height / ( m_items.Count – m_numDisplayedItems + 1 );
for ( int j = 0; j < 4; j++ )
{

m_scrollMarker[j].Y = m_quads[(int)Section.ScrollBody].Y + (float)m_topItem * (float)divisionHeight;

}

float newY = ( i – m_topItem ) * m_itemHeight + (int)m_quads[(int)Section.Background].Y;
m_normalHighlights[i].Y = newY;
m_disabledHighlights[i].Y = newY;
m_normalHighlights[i].Color = m_highlightColor;
m_disabledHighlights[i].Color = m_disabledHighlightColor;

if ( !( this is ComboBox ) )
{

BuildText();

}

}
return id;

}

/// <summary>Gets whether a new item has been selected.</summary>
public bool HasNewData Toggle

{

get { return m_newData; }

}

}

The ListBox is a menu of ListableItems with a scroll bar on the right side. I’ll start at the top and go through the methods that need some explanations. The data of a ListBox is an ArrayList of objects. The ListBox class supports both single selection and multi selection capabilities. When only a single selection is allowed, the first element of the ArrayList will hold the ListBox’s data. When multiple selections are allowed, the ArrayList will grow or shrink depending on what is selected. To support both capabilities in one class, I created another List of Quads, which will hold a highlight for each item. When we add an item with AddItem, we add the item to the List of ListableItems as well as add a new highlight onto the List of highlights.

The scroll bar logic is a bit tedious to explain so I’ll just go over it briefly. You should read through the code to understand it better. The scroll bar is divided into a number of sections that is equal to the number of times you can scroll down from the top of the list. The height of the scroll marker is equal to the height of one of these sections. However, the scroll marker does have a minimum height to prevent it from getting too small. When we drag the scroll marker, we have to keep track of a few things. First, we have to constrain its movement to stay within the bounds of the scroll body. Second, whenever the marker passes the border of one of the divided sections, we have to scroll the menu to that corresponding section. To scroll the menu, we have a top item variable. This variable is used to…duh…keep track of the top item of the displayed List. When we build the menu text in BuildText, we start at the index of m_topItem to iterate through the list. A bonus of the BitmapFont class is that it will automatically crop text within a rectangle. So if we use a rectangle the same size as the menu, BitmapFont will automatically create_ text to fit within the menu. The ScrollUp and ScrollDown, as well as the OnZDelta, methods simply move the menu one section at a time.

The OnMouseOver method simply switches out different graphics depending on where the mouse is located. This lets us see the mouse over effects on the scroll buttons. The OnMouseDown method mostly just scrolls the menu, which was explained above. It also swaps in some down state graphics much like OnMouseOver. The OnMouseRelease method is used to select or deselect items. In order to do this, we have to map the mouse cursor relative to the menu and then calculate which item the mouse clicked on. This involves some basic math that includes the position of the ListBox, the top item, and the mouse position. The difference between single selection and multi selection ListBoxes occurs in OnMouseRelease. In single selection mode, when a new item is selected, any previously selected item is deselected. In multi selection mode, the new item is just added to the list of selected items.

Along with all the previously explained code is the highlight manipulation code. Whenever we scroll the menu, we have to scroll all the highlights also. And when we select an item, we have to toggle that highlight’s visibility and move it into place.

The ListBox class contains some other useful methods such as ContainsItem, which checks if an item is already in the ListBox. SelectItem allows you to select a ListBox’s item by code. And Clear will clear all the contents of the ListBox.

Next, we’ll go over ComboBoxes.

public class ComboBox : ListBox
{

protected bool m_isOpen;
protected int m_selectedItem;
protected float m_openHeight;
// Open quads will be m_quads since it’s already implemented in ListBox
protected List<Quad> m_normalQuads;
protected List<Quad> m_overQuads;
protected List<Quad> m_disabledClosedQuads;

protected enum Box
{

Left, Right, Top, Bottom, Background, TopLeft, TopRight,
BottomLeft, BottomRight, OpenArrow

};

protected new enum Section
{

Left, Right, Top, Bottom, Background, TopLeft, TopRight,
BottomLeft, BottomRight, ScrollUp, ScrollDown, ScrollBody,
ScrollMarker, OpenArrow

};
protected new enum HotSpot { Background, ScrollUp, ScrollDown, ScrollMarker, ScrollBody, Box };

/// <summary>Creates a ListBox</summary>
/// <param name=”id”>Control ID</param>
/// <param name=”screenRect”>Screen rectangle</param>
/// <param name=”fontSize”>Font size</param>
/// <param name=”textColor”>Text color</param>
/// <param name=”font”>Bitmap Font</param>
/// <param name=”node”>ControlNode from XML file</param>
/// <param name=”info”>Texture ImageInformation</param>
public ComboBox( int id, RectangleF screenRect, float openHeight, float fontSize, ColorValue textColor, BitmapFont font, ControlNode node, ImageInformation info ) Toggle

{

m_singleItemListBox = true;
m_isOpen = false;
m_topItem = 0;
m_id = id;
m_fontSize = fontSize;
m_itemHeight = 0f;
m_textColor = textColor;
m_bFont = font;
m_scrolling = false;
m_overState = false;
m_singleItemListBox = true;
// Fill m_text up with dummy text so the FontQuads are picked up by GuiManager
m_text = “x”;
m_selectedItem = -1;
m_position = new PointF( screenRect.X, screenRect.Y );
m_size = new SizeF( screenRect.Width, screenRect.Height );
m_openHeight = openHeight;
if ( m_openHeight <= m_size.Height )
{

throw new Exception( “ComboBox open height must be greater than closed height.” );

}
m_data = new ArrayList();

int index = m_bFont.AddString( “x”, new RectangleF( 0f, 0f, 0f, 0f ), BitmapFont.Align.Left, m_fontSize, m_textColor, true );
m_itemHeight = m_bFont.GetLineHeight( index );
m_bFont.ClearString( index );

m_scrollUp = new List<Quad>();
m_scrollDown = new List<Quad>();
m_scrollMarker = new List<Quad>();
m_quads = new List<Quad>();
m_disabledQuads = new List<Quad>();
m_normalHighlights = new List<Quad>();
m_disabledHighlights = new List<Quad>();
m_highlightQuads = new List<Quad>();
m_items = new List<ListableItem>();
m_hotspots = new List<Rectangle>();
m_normalQuads = new List<Quad>();
m_overQuads = new List<Quad>();
m_disabledClosedQuads = new List<Quad>();

// Initialize Lists so we can access them with indices
m_highlightQuads.Add( new Quad() );
m_highlightQuads.Add( new Quad() );
for ( int i = 0; i < 6; i++ )
{

m_hotspots.Add( new Rectangle() );

}
for ( int i = 0; i < 4; i++ )
{

m_scrollUp.Add( new Quad() );
m_scrollDown.Add( new Quad() );
m_scrollMarker.Add( new Quad() );

}
for ( int i = 0; i < 13; i++ )
{

m_quads.Add( new Quad() );

}
// m_disabledQuads aren’t used in ComboBox but are used in ListBox, so
// initialize the List so ListBox will still work
TransformedColoredTextured t = new TransformedColoredTextured( 0f, 0f, 0f, 0f, 0, 0f, 0f );
for ( int i = 0; i < 13; i++ )
{

m_disabledQuads.Add( new Quad( t, t, t, t ) );

}
for ( int i = 0; i < 10; i++ )
{

m_normalQuads.Add( new Quad() );
m_overQuads.Add( new Quad() );
m_disabledClosedQuads.Add( new Quad() );

}

float z = 0f;
float rhw = 1f;
foreach ( ImageNode i in node.Images )
{

RectangleF rect = i.Rectangle;

TransformedColoredTextured topLeft = new TransformedColoredTextured(
screenRect.X, screenRect.Y, z, rhw,
i.Color, rect.X / (float)info.Width, rect.Y / (float)info.Height );
TransformedColoredTextured topRight = new TransformedColoredTextured(
screenRect.X + rect.Width, screenRect.Y, z, rhw,
i.Color, rect.Right / (float)info.Width, rect.Y / (float)info.Height );
TransformedColoredTextured bottomRight = new TransformedColoredTextured(
screenRect.X + rect.Width, screenRect.Y + rect.Height, z, rhw,
i.Color, rect.Right / (float)info.Width, rect.Bottom / (float)info.Height );
TransformedColoredTextured bottomLeft = new TransformedColoredTextured(
screenRect.X, screenRect.Y + rect.Height, z, rhw,
i.Color, rect.X / (float)info.Width, rect.Bottom / (float)info.Height );
Quad q = new Quad( topLeft, topRight, bottomLeft, bottomRight );
if ( i.Name.EndsWith( “TopLeftCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.TopLeft] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.TopLeft] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.TopLeft] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.TopLeft] = q;

}

}
else if ( i.Name.EndsWith( “TopBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.Top] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.Top] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.Top] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.Top] = q;

}

}
else if ( i.Name.EndsWith( “TopRightCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.TopRight] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.TopRight] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.TopRight] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.TopRight] = q;

}

}
else if ( i.Name.EndsWith( “LeftBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.Left] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.Left] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.Left] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.Left] = q;

}

}
else if ( i.Name.EndsWith( “Background” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.Background] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.Background] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.Background] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.Background] = q;

}

}
else if ( i.Name.EndsWith( “RightBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.Right] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.Right] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.Right] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.Right] = q;

}

}
else if ( i.Name.EndsWith( “BottomLeftCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.BottomLeft] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.BottomLeft] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.BottomLeft] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.BottomLeft] = q;

}

}
else if ( i.Name.EndsWith( “BottomBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.Bottom] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.Bottom] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.Bottom] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.Bottom] = q;

}

}
else if ( i.Name.EndsWith( “BottomRightCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.BottomRight] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.BottomRight] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.BottomRight] = q;

}
else if ( i.Name.StartsWith( “List” ) )
{

m_quads[(int)Section.BottomRight] = q;

}

}
else if ( i.Name.EndsWith( “OpenArrow” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_normalQuads[(int)Box.OpenArrow] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_overQuads[(int)Box.OpenArrow] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledClosedQuads[(int)Box.OpenArrow] = q;

}

}
else if ( i.Name == “ListScrollBody” )
{

m_quads[(int)Section.ScrollBody] = q;

}
else if ( i.Name == “ListHighlight” )
{

m_highlightQuads[(int)Highlight.Normal] = q;
m_highlightColor = i.Color.ToArgb();
// Dummy Disabled highlight for ListBox implementation
m_highlightQuads[(int)Highlight.Disabled] = (Quad)q.Clone();

}
else if ( i.Name.EndsWith( “ScrollUp” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.ScrollUp] = q;
m_scrollUp[(int)ControlState.Normal] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_scrollUp[(int)ControlState.Over] = q;

}
else if ( i.Name.StartsWith( “Down” ) )
{

m_scrollUp[(int)ControlState.Down] = q;

}
// Junk for inherited ListBox
m_scrollUp[(int)ControlState.Disabled] = (Quad)q.Clone();

}
else if ( i.Name.EndsWith( “ScrollDown” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.ScrollDown] = q;
m_scrollDown[(int)ControlState.Normal] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_scrollDown[(int)ControlState.Over] = q;

}
else if ( i.Name.StartsWith( “Down” ) )
{

m_scrollDown[(int)ControlState.Down] = q;

}
// Junk for inherited ListBox
m_scrollDown[(int)ControlState.Disabled] = (Quad)q.Clone();

}
else if ( i.Name.EndsWith( “ScrollMarker” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.ScrollMarker] = q;
m_scrollMarker[(int)ControlState.Normal] = q;

}
else if ( i.Name.StartsWith( “Over” ) )
{

m_scrollMarker[(int)ControlState.Over] = q;

}
else if ( i.Name.StartsWith( “Down” ) )
{

m_scrollMarker[(int)ControlState.Down] = q;

}
// Junk for inherited ListBox
m_scrollMarker[(int)ControlState.Disabled] = (Quad)q.Clone();

}

}

PositionQuads();

}

/// <summary>Checks is the mouse is over the Control’s hotspot</summary>
/// <param name=”cursor”>Mouse position</param>
/// <returns>true if the cursor is over the Control’s hotspot, false otherwise.</returns>
public override bool Contains( Point cursor ) Toggle

{

if ( m_isOpen )
{

foreach ( Rectangle r in m_hotspots )
{

if ( r.Contains( cursor ) )
{

return true;

}

}
if ( m_overState )
{

m_overState = false;
m_quads[(int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Normal];
m_quads[(int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Normal];
m_quads[(int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Normal];

}

}
else if ( m_hotspots[(int)HotSpot.Box].Contains( cursor ) )
{

return true;

}
return false;

}

/// <summary>Mouse Over event</summary>
/// <param name=”cursor”>Mouse position</param>
/// <param name=”buttons”>Mouse buttons</param>
protected override void OnMouseOver( Point cursor, bool[] buttons ) Toggle

{

if ( m_isOpen )
{

// Create rollover effect
if ( m_hotspots[(int)HotSpot.ScrollUp].Contains( cursor ) )
{

m_overState = true;
m_overQuads[10 + (int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Over];

}
else
{

m_overQuads[10 + (int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Normal];

}
if ( m_hotspots[(int)HotSpot.ScrollDown].Contains( cursor ) )
{

m_overState = true;
m_overQuads[10 + (int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Over];

}
else
{

m_overQuads[10 + (int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Normal];

}
if ( m_hotspots[(int)HotSpot.ScrollMarker].Contains( cursor ) )
{

m_overState = true;
m_overQuads[10 + (int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Over];

}
else
{

m_overQuads[10 + (int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Normal];

}

// Move highlight along with mouse
int highlightedItem = ( cursor.Y – (int)m_quads[(int)Section.Background].Y ) / (int)m_itemHeight;
if ( m_hotspots[(int)HotSpot.Background].Contains( cursor ) )
{

if ( ( highlightedItem < m_numDisplayedItems ) && ( highlightedItem + m_topItem < m_items.Count ) )
{

int highlight = 0;
if ( m_selectedItem >= 0 )
{

highlight = m_selectedItem;

}
highlightedItem += m_topItem;
float newY = ( highlightedItem – m_topItem ) * m_itemHeight + (int)m_quads[(int)Section.Background].Y;
m_normalHighlights[highlight].Y = newY;
m_normalHighlights[highlight].Color = m_highlightColor;

}

}

}

}

/// <summary>Mouse Down event</summary>
/// <param name=”cursor”>Mouse position</param>
/// <param name=”buttons”>Mouse buttons</param>
protected override void OnMouseDown( Point cursor, bool[] buttons ) Toggle

{

if ( m_isOpen )
{

base.OnMouseDown( cursor, buttons );

// Create pushdown effect
if ( m_hotspots[(int)HotSpot.ScrollUp].Contains( cursor ) && !m_hasFocus )
{

m_overQuads[10 + (int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Down];

}
else if ( !m_hasFocus )
{

m_overQuads[10 + (int)Section.ScrollUp] = m_scrollUp[(int)ControlState.Normal];

}
if ( m_hotspots[(int)HotSpot.ScrollDown].Contains( cursor ) && !m_hasFocus )
{

m_overQuads[10 + (int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Down];

}
else if ( !m_hasFocus )
{

m_overQuads[10 + (int)Section.ScrollDown] = m_scrollDown[(int)ControlState.Normal];

}
if ( m_hotspots[(int)HotSpot.ScrollMarker].Contains( cursor ) && !m_hasFocus )
{

m_overQuads[10 + (int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Down];

}
else if ( !m_hasFocus )
{

m_overQuads[10 + (int)Section.ScrollMarker] = m_scrollMarker[(int)ControlState.Normal];

}

}

}

/// <summary>Mouse Release event</summary>
/// <param name=”cursor”>Mouse position</param>
protected override void OnMouseRelease( System.Drawing.Point cursor ) Toggle

{

m_newData = false;
if ( m_isOpen )
{

if ( m_hotspots[(int)HotSpot.ScrollDown].Contains( cursor ) )
{

ScrollDown();

}
else if ( m_hotspots[(int)HotSpot.ScrollUp].Contains( cursor ) )
{

ScrollUp();

}
else if ( m_hotspots[(int)HotSpot.Background].Contains( cursor ) )
{

int highlightedItem = ( cursor.Y – (int)m_quads[(int)Section.Background].Y ) / (int)m_itemHeight;
if ( ( highlightedItem < m_numDisplayedItems ) && ( highlightedItem + m_topItem < m_items.Count ) )
{

highlightedItem += m_topItem;

// Check for new data
m_newData = true;
foreach ( object o in (ArrayList)m_data )
{

if ( m_items[highlightedItem].Data == o )
{

m_newData = false;
break;

}

}

m_items[highlightedItem].Selected = true;
m_selectedItem = highlightedItem;
// Turn alpha on
m_normalHighlights[highlightedItem].Color = m_highlightColor;
m_disabledHighlights[highlightedItem].Color = m_disabledHighlightColor;

// Deselect other items if a single item list box
( (ArrayList)m_data ).Clear();
for ( int i = 0; i < m_items.Count; i++ )
{

if ( i != highlightedItem )
{

m_items[i].Selected = false;
m_normalHighlights[i].Color = 0;
m_disabledHighlights[i].Color = 0;

}

}
( (ArrayList)m_data ).Add( m_items[highlightedItem].Data );
m_text = m_items[highlightedItem].Text;
float newY = ( highlightedItem – m_topItem ) * m_itemHeight + (int)m_quads[(int)Section.Background].Y;
m_normalHighlights[highlightedItem].Y = newY;
m_disabledHighlights[highlightedItem].Y = newY;
m_normalHighlights[highlightedItem].Color = m_highlightColor;
m_disabledHighlights[highlightedItem].Color = m_disabledHighlightColor;

if ( !m_scrolling )
{

m_isOpen = false;
m_overQuads.RemoveRange( 10, m_quads.Count );
BuildText();

}

}

}
else if ( m_hotspots[(int)HotSpot.Box].Contains( cursor ) && !m_scrolling || !Contains( cursor ) )
{

m_isOpen = false;
m_overQuads.RemoveRange( 10, m_quads.Count );
BuildText();

}

}
else if ( m_hotspots[(int)HotSpot.Box].Contains( cursor ) )
{

m_isOpen = true;
if ( m_selectedItem >= 0 )
{

// Highlight may be active from mouseover
m_normalHighlights[0].Color = 0;

// Turn on selected highlight and move it to position
m_normalHighlights[m_selectedItem].Color = m_highlightColor;
m_topItem = Math.Min( m_selectedItem, m_items.Count – m_numDisplayedItems );
float newY = ( m_selectedItem – m_topItem ) * m_itemHeight + (int)m_quads[(int)Section.Background].Y;
m_normalHighlights[m_selectedItem].Y = newY;

// Move Scroll Marker
int divisionHeight = (int)m_quads[(int)Section.ScrollBody].Height / ( m_items.Count – m_numDisplayedItems + 1 );
for ( int i = 0; i < 4; i++ )
{

m_scrollMarker[i].Y = m_quads[(int)Section.ScrollBody].Y + (float)m_topItem * (float)divisionHeight;

}

}

m_overQuads.AddRange( m_quads );
BuildText();

for ( int i = 0; i < 4; i++ )
{

if ( m_numDisplayedItems == m_items.Count )
{

m_scrollMarker[i].Height = 0f;

}
else
{

m_scrollMarker[i].Height = m_quads[(int)Section.ScrollBody].Height / ( (float)m_items.Count – (float)m_numDisplayedItems + 1 );
m_scrollMarker[i].Height = Math.Max( m_scrollMarker[i].Height, m_minMarkerHeight );

}

}

}
BuildHotspots();

m_scrolling = false;

}

/// <summary>Gets the Contol’s current Quads</summary>
public override List<Quad> Quads Toggle

{

get
{

switch ( m_state )
{

case ControlState.Disabled:

return m_disabledClosedQuads;

case ControlState.Over:

return m_overQuads;

case ControlState.Down:

return m_overQuads;

default:

if ( m_isOpen )
{

return m_overQuads;

}
return m_normalQuads;

}

}

}

/// <summary>Gets and sets the Panel’s position</summary>
public override PointF Position Toggle

{

get { return m_position; }
set
{

float xOffset = value.X – m_position.X;
float yOffset = value.Y – m_position.Y;
m_position = value;
for ( int i = 0; i < m_normalQuads.Count; i++ )
{

m_normalQuads[i].X += xOffset;
m_normalQuads[i].Y += yOffset;
m_overQuads[i].X += xOffset;
m_overQuads[i].Y += yOffset;
m_disabledClosedQuads[i].X += xOffset;
m_disabledClosedQuads[i].Y += yOffset;

}
for ( int i = 0; i < m_quads.Count; i++ )
{

if ( i == (int)Section.ScrollUp || i == (int)Section.ScrollDown || i == (int)Section.ScrollMarker )
{

continue;

}
m_quads[i].X += xOffset;
m_quads[i].Y += yOffset;

}
for ( int i = 0; i < 3; i++ )
{

m_scrollUp[i].X += xOffset;
m_scrollUp[i].Y += yOffset;
m_scrollDown[i].X += xOffset;
m_scrollDown[i].Y += yOffset;
m_scrollMarker[i].X += xOffset;
m_scrollMarker[i].Y += yOffset;

}

BuildHotspots();

for ( int i = 0; i < m_fontQuads.Count; i++ )
{

m_fontQuads[i].X += xOffset;
m_fontQuads[i].Y += yOffset;

}

}

}

/// <summary>Positions the Quads</summary>
protected override void PositionQuads() Toggle

{

// Adjust box middle column X
m_normalQuads[(int)Box.Top].X = m_normalQuads[(int)Box.TopLeft].Right;
m_normalQuads[(int)Box.Background].X = m_normalQuads[(int)Box.Left].Right;
m_normalQuads[(int)Box.Bottom].X = m_normalQuads[(int)Box.BottomLeft].Right;
m_overQuads[(int)Box.Top].X = m_overQuads[(int)Box.TopLeft].Right;
m_overQuads[(int)Box.Background].X = m_overQuads[(int)Box.Left].Right;
m_overQuads[(int)Box.Bottom].X = m_overQuads[(int)Box.BottomLeft].Right;
m_disabledClosedQuads[(int)Box.Top].X = m_disabledClosedQuads[(int)Box.TopLeft].Right;
m_disabledClosedQuads[(int)Box.Background].X = m_disabledClosedQuads[(int)Box.Left].Right;
m_disabledClosedQuads[(int)Box.Bottom].X = m_disabledClosedQuads[(int)Box.BottomLeft].Right;

// Adjust box middle row Y
m_normalQuads[(int)Box.Left].Y = m_normalQuads[(int)Box.TopLeft].Bottom;
m_normalQuads[(int)Box.Background].Y = m_normalQuads[(int)Box.Top].Bottom;
m_normalQuads[(int)Box.Right].Y = m_normalQuads[(int)Box.TopRight].Bottom;
m_overQuads[(int)Box.Left].Y = m_overQuads[(int)Box.TopLeft].Bottom;
m_overQuads[(int)Box.Background].Y = m_overQuads[(int)Box.Top].Bottom;
m_overQuads[(int)Box.Right].Y = m_overQuads[(int)Box.TopRight].Bottom;
m_disabledClosedQuads[(int)Box.Left].Y = m_disabledClosedQuads[(int)Box.TopLeft].Bottom;
m_disabledClosedQuads[(int)Box.Background].Y = m_disabledClosedQuads[(int)Box.Top].Bottom;
m_disabledClosedQuads[(int)Box.Right].Y = m_disabledClosedQuads[(int)Box.TopRight].Bottom;

// Adjust box middle row height
m_normalQuads[(int)Box.Left].Height =
m_size.Height – m_normalQuads[(int)Box.TopLeft].Height –
m_normalQuads[(int)Box.BottomLeft].Height;
m_normalQuads[(int)Box.Background].Height =
m_size.Height – m_normalQuads[(int)Box.Top].Height –
m_normalQuads[(int)Box.Bottom].Height;
m_normalQuads[(int)Box.Right].Height =
m_size.Height – m_quads[(int)Section.TopRight].Height –
m_normalQuads[(int)Box.BottomRight].Height;

m_overQuads[(int)Box.Left].Height =
m_size.Height – m_overQuads[(int)Box.TopLeft].Height –
m_overQuads[(int)Box.BottomLeft].Height;
m_overQuads[(int)Box.Background].Height =
m_size.Height – m_overQuads[(int)Box.Top].Height –
m_overQuads[(int)Box.Bottom].Height;
m_overQuads[(int)Box.Right].Height =
m_size.Height – m_quads[(int)Section.TopRight].Height –
m_overQuads[(int)Box.BottomRight].Height;

m_disabledClosedQuads[(int)Box.Left].Height =
m_size.Height – m_disabledClosedQuads[(int)Box.TopLeft].Height –
m_disabledClosedQuads[(int)Box.BottomLeft].Height;
m_disabledClosedQuads[(int)Box.Background].Height =
m_size.Height – m_disabledClosedQuads[(int)Box.Top].Height –
m_disabledClosedQuads[(int)Box.Bottom].Height;
m_disabledClosedQuads[(int)Box.Right].Height =
m_size.Height – m_quads[(int)Section.TopRight].Height –
m_disabledClosedQuads[(int)Box.BottomRight].Height;

// Adjust box bottom row Y
m_normalQuads[(int)Box.BottomLeft].Y = m_normalQuads[(int)Box.Left].Bottom;
m_normalQuads[(int)Box.Bottom].Y = m_normalQuads[(int)Box.Background].Bottom;
m_normalQuads[(int)Box.BottomRight].Y = m_normalQuads[(int)Box.Right].Bottom;
m_overQuads[(int)Box.BottomLeft].Y = m_overQuads[(int)Box.Left].Bottom;
m_overQuads[(int)Box.Bottom].Y = m_overQuads[(int)Box.Background].Bottom;
m_overQuads[(int)Box.BottomRight].Y = m_overQuads[(int)Box.Right].Bottom;
m_disabledClosedQuads[(int)Box.BottomLeft].Y = m_disabledClosedQuads[(int)Box.Left].Bottom;
m_disabledClosedQuads[(int)Box.Bottom].Y = m_disabledClosedQuads[(int)Box.Background].Bottom;
m_disabledClosedQuads[(int)Box.BottomRight].Y = m_disabledClosedQuads[(int)Box.Right].Bottom;

// Adjust open arrow dimensions
m_normalQuads[(int)Box.OpenArrow].Height = m_normalQuads[(int)Box.Bottom].Bottom – m_normalQuads[(int)Box.Top].Y;
m_overQuads[(int)Box.OpenArrow].Height = m_overQuads[(int)Box.Bottom].Bottom – m_overQuads[(int)Box.Top].Y;
m_disabledClosedQuads[(int)Box.OpenArrow].Height = m_disabledClosedQuads[(int)Box.Bottom].Bottom – m_disabledClosedQuads[(int)Box.Top].Y;

m_normalQuads[(int)Box.OpenArrow].Width = m_normalQuads[(int)Box.OpenArrow].Height;
m_overQuads[(int)Box.OpenArrow].Width = m_overQuads[(int)Box.OpenArrow].Height;
m_disabledClosedQuads[(int)Box.OpenArrow].Width = m_disabledClosedQuads[(int)Box.OpenArrow].Height;

// Adjust box middle column width
m_normalQuads[(int)Box.Top].Width =
m_size.Width – m_normalQuads[(int)Box.TopLeft].Width –
m_normalQuads[(int)Box.TopRight].Width – m_normalQuads[(int)Box.OpenArrow].Width;
m_normalQuads[(int)Box.Background].Width =
m_size.Width – m_normalQuads[(int)Box.Left].Width –
m_normalQuads[(int)Box.Right].Width – m_normalQuads[(int)Box.OpenArrow].Width;
m_normalQuads[(int)Box.Bottom].Width =
m_size.Width – m_quads[(int)Section.BottomLeft].Width –
m_normalQuads[(int)Box.BottomRight].Width – m_normalQuads[(int)Box.OpenArrow].Width;

m_overQuads[(int)Box.Top].Width =
m_size.Width – m_overQuads[(int)Box.TopLeft].Width –
m_overQuads[(int)Box.TopRight].Width – m_overQuads[(int)Box.OpenArrow].Width;
m_overQuads[(int)Box.Background].Width =
m_size.Width – m_overQuads[(int)Box.Left].Width –
m_overQuads[(int)Box.Right].Width – m_overQuads[(int)Box.OpenArrow].Width;
m_overQuads[(int)Box.Bottom].Width =
m_size.Width – m_quads[(int)Section.BottomLeft].Width –
m_overQuads[(int)Box.BottomRight].Width – m_overQuads[(int)Box.OpenArrow].Width;

m_disabledClosedQuads[(int)Box.Top].Width =
m_size.Width – m_disabledClosedQuads[(int)Box.TopLeft].Width –
m_disabledClosedQuads[(int)Box.TopRight].Width – m_disabledClosedQuads[(int)Box.OpenArrow].Width;
m_disabledClosedQuads[(int)Box.Background].Width =
m_size.Width – m_disabledClosedQuads[(int)Box.Left].Width –
m_disabledClosedQuads[(int)Box.Right].Width – m_disabledClosedQuads[(int)Box.OpenArrow].Width;
m_disabledClosedQuads[(int)Box.Bottom].Width =
m_size.Width – m_quads[(int)Section.BottomLeft].Width –
m_disabledClosedQuads[(int)Box.BottomRight].Width – m_disabledClosedQuads[(int)Box.OpenArrow].Width;

// Adjust box right column x
m_normalQuads[(int)Box.TopRight].X = m_normalQuads[(int)Box.Top].Right;
m_normalQuads[(int)Box.Right].X = m_normalQuads[(int)Box.Background].Right;
m_normalQuads[(int)Box.BottomRight].X = m_normalQuads[(int)Box.Bottom].Right;
m_overQuads[(int)Box.TopRight].X = m_overQuads[(int)Box.Top].Right;
m_overQuads[(int)Box.Right].X = m_overQuads[(int)Box.Background].Right;
m_overQuads[(int)Box.BottomRight].X = m_overQuads[(int)Box.Bottom].Right;
m_disabledClosedQuads[(int)Box.TopRight].X = m_disabledClosedQuads[(int)Box.Top].Right;
m_disabledClosedQuads[(int)Box.Right].X = m_disabledClosedQuads[(int)Box.Background].Right;
m_disabledClosedQuads[(int)Box.BottomRight].X = m_disabledClosedQuads[(int)Box.Bottom].Right;

// Adjust open arrow
m_normalQuads[(int)Box.OpenArrow].X = m_normalQuads[(int)Box.TopRight].Right;
m_overQuads[(int)Box.OpenArrow].X = m_overQuads[(int)Box.TopRight].Right;
m_disabledClosedQuads[(int)Box.OpenArrow].X = m_disabledClosedQuads[(int)Box.TopRight].Right;

m_quads[(int)Section.TopLeft].Y = m_overQuads[(int)Box.BottomLeft].Bottom;
m_quads[(int)Section.Top].Y = m_overQuads[(int)Box.Bottom].Bottom;
m_quads[(int)Section.TopRight].Y = m_overQuads[(int)Box.BottomRight].Bottom;
for ( int i = 0; i < 4; i++ )
{

m_scrollUp[i].Y = m_overQuads[(int)Box.OpenArrow].Bottom;

}

float oldHeight = m_size.Height;
m_size.Height = m_openHeight – m_size.Height;
base.PositionQuads();
m_size.Height = oldHeight;

}

/// <summary>Builds the hotspots</summary>
protected override void BuildHotspots() Toggle

{

m_hotspots[(int)HotSpot.Background] = new Rectangle(
(int)m_quads[(int)Section.Background].X,
(int)m_quads[(int)Section.Background].Y,
(int)m_quads[(int)Section.Background].Width,
(int)m_quads[(int)Section.Background].Height );

m_hotspots[(int)HotSpot.ScrollBody] = new Rectangle(
(int)m_quads[(int)Section.ScrollBody].X,
(int)m_quads[(int)Section.ScrollBody].Y,
(int)m_quads[(int)Section.ScrollBody].Width,
(int)m_quads[(int)Section.ScrollBody].Height );

m_hotspots[(int)HotSpot.ScrollUp] = new Rectangle(
(int)m_quads[(int)Section.ScrollUp].X,
(int)m_quads[(int)Section.ScrollUp].Y,
(int)m_quads[(int)Section.ScrollUp].Width,
(int)m_quads[(int)Section.ScrollUp].Height );

m_hotspots[(int)HotSpot.ScrollDown] = new Rectangle(
(int)m_quads[(int)Section.ScrollDown].X,
(int)m_quads[(int)Section.ScrollDown].Y,
(int)m_quads[(int)Section.ScrollDown].Width,
(int)m_quads[(int)Section.ScrollDown].Height );

m_hotspots[(int)HotSpot.ScrollMarker] = new Rectangle(
(int)m_quads[(int)Section.ScrollMarker].X,
(int)m_quads[(int)Section.ScrollMarker].Y,
(int)m_quads[(int)Section.ScrollMarker].Width,
(int)m_quads[(int)Section.ScrollMarker].Height );

m_hotspots[(int)HotSpot.Box] = new Rectangle(
(int)m_normalQuads[(int)Box.TopLeft].X,
(int)m_normalQuads[(int)Box.TopLeft].Y,
(int)m_normalQuads[(int)Box.OpenArrow].Right – (int)m_normalQuads[(int)Box.Left].X,
(int)m_normalQuads[(int)Box.Bottom].Bottom – (int)m_normalQuads[(int)Box.Top].Y );

}

/// <summary>Builds the text</summary>
protected override void BuildText() Toggle

{

m_fontQuads = new List<Quad>();

// Add selected item text
if ( m_selectedItem >= 0 )
{

float y = m_normalQuads[(int)Box.Background].Y +
( m_normalQuads[(int)Box.Background].Height / 2f ) – ( m_itemHeight / 2f );
int index = m_bFont.AddString( m_items[m_selectedItem].Text, new RectangleF(
m_normalQuads[(int)Box.Background].X + 2f, y,
m_quads[(int)Section.Background].Width, m_quads[(int)Section.Background].Height ),
BitmapFont.Align.Left, m_fontSize, m_textColor, true );
List<FontQuad> selectedFontQuads = m_bFont.GetProcessedQuads( index );
m_bFont.ClearString( index );

// Convert FontQuads to Quads
for ( int j = 0; j < selectedFontQuads.Count; j++ )
{

m_fontQuads.Add( new Quad( selectedFontQuads[j].TopLeft, selectedFontQuads[j].TopRight, selectedFontQuads[j].BottomLeft, selectedFontQuads[j].BottomRight ) );

}

}

if ( m_isOpen )
{

string text = “”;
for ( int i = m_topItem; i < m_items.Count; i++ )
{

text += m_items[i].Text + “n”;

}
int index = m_bFont.AddString( text, new RectangleF(
m_quads[(int)Section.Background].X + 2f, m_quads[(int)Section.Background].Y,
m_quads[(int)Section.Background].Width, m_quads[(int)Section.Background].Height ),
BitmapFont.Align.Left, m_fontSize, m_textColor, true );
List<FontQuad> fontQuads = m_bFont.GetProcessedQuads( index );
m_bFont.ClearString( index );

// Highlight height is dependent on line height
float highlightHeight = m_itemHeight;
for ( int i = 0; i < m_normalHighlights.Count; i++ )
{

m_normalHighlights[i].Height = highlightHeight;
m_disabledHighlights[i].Height = highlightHeight;

}

// Convert FontQuads to Quads
for ( int j = 0; j < fontQuads.Count; j++ )
{

m_fontQuads.Add( new Quad( fontQuads[j].TopLeft, fontQuads[j].TopRight, fontQuads[j].BottomLeft, fontQuads[j].BottomRight ) );

}

}

}

/// <summary>Selects an item.</summary>
/// <param name=”itemText”>Item text</param>
/// <returns>ID of the selected item.</returns>
public override int SelectItem( string itemText ) Toggle

{

m_selectedItem = base.SelectItem( itemText );

BuildText();

m_topItem = Math.Min( m_selectedItem, m_items.Count – m_numDisplayedItems );

return m_selectedItem;

}

/// <summary>Clears the ComboBox’s selected item.</summary>
public override void Clear() Toggle

{

base.Clear();
m_selectedItem = -1;
BuildText();

}

/// <summary>Gets and sets whether the ComboBox is open.</summary>
public bool IsOpen Toggle

{

get { return m_isOpen; }
set
{

if ( value && !m_isOpen )
{

m_overQuads.AddRange( m_quads );

}
else if ( !value && m_isOpen )
{

m_overQuads.RemoveRange( 10, m_quads.Count );

}
m_isOpen = value;
BuildText();

}

}

}

A ComboBox is basically a ListBox that opens and closes. Therefore, ComboBox inherits from ListBox. Most of the logic behind a ComboBox was explained in the ListBoxes section so there isn’t as much to say. The selected item’s text is displayed in the little text section at the top of the ComboBox.

Some features of the ComboBox include the highlight moving with the mouse when the mouse moves over the open menu. Also, when an item is currently selected and the menu opens, the menu will automatically be scrolled to the selected item.

Since ComboBox’s and ListBoxes share most of the same explanations, we’ll move onto the last Control, EditBoxes:

public class EditBox : Control
{

private const int Backspace = (int)System.Windows.Forms.Keys.Back;
private const int Delete = (int)System.Windows.Forms.Keys.Delete;
private const int Left = (int)System.Windows.Forms.Keys.Left;
private const int Right = (int)System.Windows.Forms.Keys.Right;
private const int End = (int)System.Windows.Forms.Keys.End;
private const int Home = (int)System.Windows.Forms.Keys.Home;
private const int Return = (int)System.Windows.Forms.Keys.Return;

private List<Quad> m_disabledQuads;
private Quad m_cursor;
private int m_cursorPosition;
private int m_maxLength;
private enum Section { Left, Right, Top, Bottom, Background, TopLeft, TopRight, BottomLeft, BottomRight };

/// <summary>Creates an EditBox</summary>
/// <param name=”id”>Control ID</param>
/// <param name=”screenRect”>Screen rectangle</param>
/// <param name=”text”>EditBox text</param>
/// <param name=”fontSize”>Font size</param>
/// <param name=”maxLength”>Max number of characters allowed in the edit box.</param>
/// <param name=”textColor”>Text color</param>
/// <param name=”font”>Bitmap font</param>
/// <param name=”node”>ControlNode from XML file</param>
/// <param name=”info”>Texture ImageInformation</param>
public EditBox( int id, RectangleF screenRect, string text, float fontSize, int maxLength, ColorValue textColor, BitmapFont font, ControlNode node, ImageInformation info ) Toggle

{

m_id = id;
if ( text.Length > maxLength )
{

text.Remove( maxLength – 1 );

}
m_text = text;
m_data = text;
m_fontSize = fontSize;
m_textColor = textColor;
m_bFont = font;
m_position = new PointF( screenRect.X, screenRect.Y );
m_size = new SizeF( screenRect.Width, screenRect.Height );
m_cursorPosition = 0;
m_maxLength = maxLength;

m_quads = new List<Quad>();
m_disabledQuads = new List<Quad>();

// Initialize Lists so we can access them with indices
for ( int i = 0; i < 9; i++ )
{

m_quads.Add( new Quad() );
m_disabledQuads.Add( new Quad() );

}

float z = 0f;
float rhw = 1f;
foreach ( ImageNode i in node.Images )
{

RectangleF rect = i.Rectangle;

TransformedColoredTextured topLeft = new TransformedColoredTextured(
screenRect.X, screenRect.Y, z, rhw,
i.Color, rect.X / (float)info.Width, rect.Y / (float)info.Height );
TransformedColoredTextured topRight = new TransformedColoredTextured(
screenRect.X + rect.Width, screenRect.Y, z, rhw,
i.Color, rect.Right / (float)info.Width, rect.Y / (float)info.Height );
TransformedColoredTextured bottomRight = new TransformedColoredTextured(
screenRect.X + rect.Width, screenRect.Y + rect.Height, z, rhw,
i.Color, rect.Right / (float)info.Width, rect.Bottom / (float)info.Height );
TransformedColoredTextured bottomLeft = new TransformedColoredTextured(
screenRect.X, screenRect.Y + rect.Height, z, rhw,
i.Color, rect.X / (float)info.Width, rect.Bottom / (float)info.Height );
Quad q = new Quad( topLeft, topRight, bottomLeft, bottomRight );
if ( i.Name.EndsWith( “TopLeftCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.TopLeft] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.TopLeft] = q;

}

}
else if ( i.Name.EndsWith( “TopBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Top] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Top] = q;

}

}
else if ( i.Name.EndsWith( “TopRightCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.TopRight] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.TopRight] = q;

}

}
else if ( i.Name.EndsWith( “LeftBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Left] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Left] = q;

}

}
else if ( i.Name.EndsWith( “Background” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Background] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Background] = q;

}

}
else if ( i.Name.EndsWith( “RightBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Right] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Right] = q;

}

}
else if ( i.Name.EndsWith( “BottomLeftCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.BottomLeft] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.BottomLeft] = q;

}

}
else if ( i.Name.EndsWith( “BottomBorder” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.Bottom] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.Bottom] = q;

}

}
else if ( i.Name.EndsWith( “BottomRightCorner” ) )
{

if ( i.Name.StartsWith( “Normal” ) )
{

m_quads[(int)Section.BottomRight] = q;

}
else if ( i.Name.StartsWith( “Disabled” ) )
{

m_disabledQuads[(int)Section.BottomRight] = q;

}

}
else if ( i.Name == “NormalCursor” )
{

m_cursor = q;

}

}

PositionQuads();

}

/// <summary>Mouse Release event</summary>
/// <param name=”cursor”>Mouse position</param>
protected override void OnMouseRelease( Point cursor ) Toggle

{

if ( m_hasFocus )
{

// Add cursor
if ( m_quads.Count == 9 )
{

m_quads.Add( m_cursor );

}

}
else
{

// Remove cursor
m_quads.RemoveAt( 9 );

}

}

/// <summary>Releases EditBox focus</summary>
public void ReleaseFocus() Toggle

{

if ( m_hasFocus )
{

m_hasFocus = false;
// Remove cursor
m_quads.RemoveAt( 9 );

}

}

/// <summary>Key down handler.</summary>
/// <param name=”pressedKeys”>List of pressed keys</param>
/// <param name=”pressedChar”>Pressed character</param>
/// <param name=”pressedKey”>Pressed key from Form used for repeatable keys</param>
/// <returns>true if a Control processed the keyboard, false otherwise</returns>
public override bool OnKeyDown( List<Keys> pressedKeys, char pressedChar, int pressedKey ) Toggle

{

if ( !m_hasFocus )
{

return false;

}
// Non-displayable character
if ( pressedKey == Backspace )
{

if ( m_cursorPosition > 0 )
{

m_cursorPosition–;
m_text = m_text.Remove( m_cursorPosition, 1 );

}

}
else if ( pressedKey == Delete )
{

if ( m_cursorPosition < m_text.Length )
{

m_text = m_text.Remove( m_cursorPosition, 1 );

}

}
else if ( pressedKey == Left )
{

if ( m_cursorPosition <= 0 )
{

return false;

}
if ( pressedKeys.Contains( Keys.ControlKey ) )
{

if ( m_text[m_cursorPosition - 1] == ‘ ‘ )
{

while ( m_cursorPosition != 0 && m_text[m_cursorPosition - 1] == ‘ ‘ )
{

m_cursorPosition–;

}

}
else
{

while ( m_cursorPosition != 0 && m_text[m_cursorPosition - 1] != ‘ ‘ )
{

m_cursorPosition–;

}

}

}
else
{

m_cursorPosition–;

}

}
else if ( pressedKey == Right )
{

if ( m_cursorPosition >= m_text.Length )
{

return false;

}
if ( pressedKeys.Contains( Keys.ControlKey ) )
{

if ( m_text[m_cursorPosition] == ‘ ‘ )
{

while ( m_cursorPosition < m_text.Length && m_text[m_cursorPosition] == ‘ ‘ )
{

m_cursorPosition++;

}

}
else
{

while ( m_cursorPosition < m_text.Length && m_text[m_cursorPosition] != ‘ ‘ )
{

m_cursorPosition++;

}

}

}
else
{

m_cursorPosition++;

}

}
else if ( pressedKey == End )
{

m_cursorPosition = m_text.Length;

}
else if ( pressedKey == Home )
{

m_cursorPosition = 0;

}
else if ( pressedKey == Return )
{

ReleaseFocus();
return true;

}

if ( char.IsLetterOrDigit( pressedChar ) || char.IsPunctuation( pressedChar ) || char.IsSymbol( pressedChar ) || char.IsWhiteSpace( pressedChar ) )
{

if ( m_text.Length < m_maxLength && pressedChar != char.MinValue )
{

if ( m_cursorPosition == m_text.Length )
{

m_text += pressedChar.ToString();

}
else
{

m_text = m_text.Insert( m_cursorPosition, pressedChar.ToString() );

}
m_cursorPosition++;

}

}

m_data = m_text;
BuildText();
return true;

}

/// <summary>Gets and sets the Panel’s position</summary>
public override PointF Position Toggle

{

get { return m_position; }
set
{

float xOffset = value.X – m_position.X;
float yOffset = value.Y – m_position.Y;
m_position = value;

for ( int i = 0; i < 9; i++ )
{

m_quads[i].X += xOffset;
m_quads[i].Y += yOffset;
m_disabledQuads[i].X += xOffset;
m_disabledQuads[i].Y += yOffset;

}
for ( int i = 0; i < m_fontQuads.Count; i++ )
{

m_fontQuads[i].X += xOffset;
m_fontQuads[i].Y += yOffset;

}
m_cursor.X += xOffset;
m_cursor.Y += yOffset;
BuildHotspot();

}

}

/// <summary>Repositions the hot spot and text</summary>
private void PositionQuads() Toggle

{

// Adjust middle column x
m_quads[(int)Section.Top].X = m_quads[(int)Section.TopLeft].Right;
m_quads[(int)Section.Background].X = m_quads[(int)Section.Left].Right;
m_quads[(int)Section.Bottom].X = m_quads[(int)Section.BottomLeft].Right;
m_disabledQuads[(int)Section.Top].X = m_disabledQuads[(int)Section.TopLeft].Right;
m_disabledQuads[(int)Section.Background].X = m_disabledQuads[(int)Section.Left].Right;
m_disabledQuads[(int)Section.Bottom].X = m_disabledQuads[(int)Section.BottomLeft].Right;

// Adjust middle column width
m_quads[(int)Section.Top].Width =
m_size.Width – m_quads[(int)Section.TopLeft].Width –
m_quads[(int)Section.TopRight].Width;
m_disabledQuads[(int)Section.Top].Width =
m_size.Width – m_disabledQuads[(int)Section.TopLeft].Width –
m_disabledQuads[(int)Section.TopRight].Width;

m_quads[(int)Section.Background].Width =
m_size.Width – m_quads[(int)Section.Left].Width –
m_quads[(int)Section.Right].Width;
m_disabledQuads[(int)Section.Background].Width =
m_size.Width – m_disabledQuads[(int)Section.Left].Width –
m_disabledQuads[(int)Section.Right].Width;

m_quads[(int)Section.Bottom].Width =
m_size.Width – m_quads[(int)Section.BottomLeft].Width –
m_quads[(int)Section.BottomLeft].Width;
m_disabledQuads[(int)Section.Bottom].Width =
m_size.Width – m_disabledQuads[(int)Section.BottomLeft].Width –
m_disabledQuads[(int)Section.BottomLeft].Width;

// Adjust right column X
m_quads[(int)Section.TopRight].X = m_quads[(int)Section.Top].Right;
m_quads[(int)Section.Right].X = m_quads[(int)Section.Background].Right;
m_quads[(int)Section.BottomRight].X = m_quads[(int)Section.Bottom].Right;
m_disabledQuads[(int)Section.TopRight].X = m_disabledQuads[(int)Section.Top].Right;
m_disabledQuads[(int)Section.Right].X = m_disabledQuads[(int)Section.Background].Right;
m_disabledQuads[(int)Section.BottomRight].X = m_disabledQuads[(int)Section.Bottom].Right;

// Adjust middle row Y
m_quads[(int)Section.Left].Y = m_quads[(int)Section.TopLeft].Bottom;
m_quads[(int)Section.Background].Y = m_quads[(int)Section.Top].Bottom;
m_quads[(int)Section.Right].Y = m_quads[(int)Section.TopRight].Bottom;
m_disabledQuads[(int)Section.Left].Y = m_disabledQuads[(int)Section.TopLeft].Bottom;
m_disabledQuads[(int)Section.Background].Y = m_disabledQuads[(int)Section.Top].Bottom;
m_disabledQuads[(int)Section.Right].Y = m_disabledQuads[(int)Section.TopRight].Bottom;

// Adjust middle row height
m_quads[(int)Section.Left].Height =
m_size.Height – m_quads[(int)Section.TopLeft].Height –
m_quads[(int)Section.BottomLeft].Height;
m_disabledQuads[(int)Section.Left].Height =
m_size.Height – m_disabledQuads[(int)Section.TopLeft].Height –
m_disabledQuads[(int)Section.BottomLeft].Height;

m_quads[(int)Section.Background].Height =
m_size.Height – m_quads[(int)Section.Top].Height –
m_quads[(int)Section.Bottom].Height;
m_disabledQuads[(int)Section.Background].Height =
m_size.Height – m_disabledQuads[(int)Section.Top].Height –
m_disabledQuads[(int)Section.Bottom].Height;

m_quads[(int)Section.Right].Height =
m_size.Height – m_quads[(int)Section.TopRight].Height –
m_quads[(int)Section.BottomRight].Height;
m_disabledQuads[(int)Section.Right].Height =
m_size.Height – m_disabledQuads[(int)Section.TopRight].Height –
m_disabledQuads[(int)Section.BottomRight].Height;

// Adjust bottom row Y
m_quads[(int)Section.BottomLeft].Y = m_quads[(int)Section.Left].Bottom;
m_quads[(int)Section.Bottom].Y = m_quads[(int)Section.Background].Bottom;
m_quads[(int)Section.BottomRight].Y = m_quads[(int)Section.Right].Bottom;
m_disabledQuads[(int)Section.BottomLeft].Y = m_disabledQuads[(int)Section.Left].Bottom;
m_disabledQuads[(int)Section.Bottom].Y = m_disabledQuads[(int)Section.Background].Bottom;
m_disabledQuads[(int)Section.BottomRight].Y = m_disabledQuads[(int)Section.Right].Bottom;

// Adjust cursor
m_cursor.Height = m_fontSize;
m_cursor.Width = 2f;

BuildHotspot();

// Place cursor at the end of the string
m_cursorPosition = m_text.Length;

BuildText();

}

/// <summary>Builds the text</summary>
protected override void BuildText() Toggle

{

int index = m_bFont.AddString( m_text, new RectangleF( m_quads[(int)Section.Background].X + 2f,
m_quads[(int)Section.Background].Y + 2f, m_quads[(int)Section.Background].Width,
m_quads[(int)Section.Background].Height ), BitmapFont.Align.Left, m_fontSize, m_textColor, true );
List<FontQuad> fontQuads = m_bFont.GetProcessedQuads( index );
m_bFont.ClearString( index );

// Convert FontQuads to Quads
m_fontQuads = new List<Quad>( fontQuads.Count );
for ( int i = 0; i < fontQuads.Count; i++ )
{

m_fontQuads.Add( new Quad( fontQuads[i].TopLeft, fontQuads[i].TopRight, fontQuads[i].BottomLeft, fontQuads[i].BottomRight ) );

}
if ( m_cursorPosition != m_text.Length )
{

m_cursor.X = fontQuads[m_cursorPosition].X – ( fontQuads[m_cursorPosition].BitmapCharacter.XOffset * fontQuads[m_cursorPosition].SizeScale );
m_cursor.Y = fontQuads[m_cursorPosition].Y – ( fontQuads[m_cursorPosition].BitmapCharacter.YOffset * fontQuads[m_cursorPosition].SizeScale );

}
else if ( m_text.Length > 0 )
{

m_cursor.X = fontQuads[m_cursorPosition - 1].X + ( fontQuads[m_cursorPosition - 1].BitmapCharacter.XAdvance * fontQuads[m_cursorPosition - 1].SizeScale );
m_cursor.Y = fontQuads[m_cursorPosition - 1].Y – ( fontQuads[m_cursorPosition - 1].BitmapCharacter.YOffset * fontQuads[m_cursorPosition - 1].SizeScale );

}
else if ( m_text.Length == 0 )
{

m_cursor.X = m_quads[(int)Section.Background].X + 2f;
m_cursor.Y = m_quads[(int)Section.Background].Y + 2f;

}

}

/// <summary>Builds the hotspot</summary>
private void BuildHotspot() Toggle

{

int hotspotWidth = (int)m_quads[(int)Section.Right].Right – (int)m_quads[(int)Section.Left].X;
int hotspotHeight = (int)m_quads[(int)Section.Bottom].Bottom – (int)m_quads[(int)Section.Top].Y;
m_hotspot = new Rectangle( (int)m_quads[(int)Section.TopLeft].X,
(int)m_quads[(int)Section.TopLeft].Y, hotspotWidth, hotspotHeight );

}

/// <summary>Gets and sets whether the Control is disabled.</summary>
public override bool Disabled Toggle

{

get
{

return base.Disabled;

}
set
{

base.Disabled = value;
if ( Disabled )
{

ReleaseFocus();

}

}

}

/// <summary>Gets the EditBox’s current Quads</summary>
public override List<Quad> Quads Toggle

{

get
{

switch ( m_state )
{

case ControlState.Disabled:

return m_disabledQuads;

default:

return m_quads;

}

}

}

/// <summary>Gets and sets the Control’s state.</summary>
public override ControlState State Toggle

{

get
{

return base.State;

}
set
{

base.State = value;
if ( Disabled )
{

ReleaseFocus();

}

}

}

}

EditBoxes allow users to enter text into your program. To implement this functionality, EditBox has a cursor position, which is an index into the string. All new characters are entered into the string at the cursor position via the string.Insert method. When the user clicks on the EditBox, the cursor Quad is added to the Control’s List of Quads, and the EditBox gains the keyboards focus.

Most of the action occurs in OnKeyDown. The OnKeyDown method adds or subtracts characters from its string. It also allows for cursor movement and string manipulation using the left and right arrow keys, ctrl + the left or right arrow keys, home, end, delete, and backspace. Just about all of the logic is pretty straight forward. Once again, the BitmapFont class provides the added bonus of cropping and wrapping the text inside the EditBox rectangle.

The EditBox class has a max length field, which limits the amount of text you want displayed in the text box. While the BitmapFont class automatically crops and wraps text within a rectangle, the max length field can further restrict the amount of text that is displayed in the EditBox.

All the Controls are now implemented. In the next tutorial, you’ll see how to use the GUI.

Home » Resources » Managed DirectX 2.0 » Creating a GUI (Part 3)

© 2010 Chad Vernon