tge/engine/gui/controls/guiListBoxCtrl.cc
2017-04-17 06:17:10 -06:00

997 lines
26 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "gui/controls/guiListBoxCtrl.h"
IMPLEMENT_CONOBJECT(GuiListBoxCtrl);
GuiListBoxCtrl::GuiListBoxCtrl()
{
mItems.clear();
mSelectedItems.clear();
mMultipleSelections = true;
mFitParentWidth = true;
mItemSize = Point2I(10,20);
mLastClickItem = NULL;
}
GuiListBoxCtrl::~GuiListBoxCtrl()
{
clearItems();
}
void GuiListBoxCtrl::initPersistFields()
{
Parent::initPersistFields();
addField( "AllowMultipleSelections", TypeBool, Offset( mMultipleSelections, GuiListBoxCtrl) );
addField( "FitParentWidth", TypeBool, Offset( mFitParentWidth, GuiListBoxCtrl) );
}
bool GuiListBoxCtrl::onWake()
{
if( !Parent::onWake() )
return false;
updateSize();
return true;
}
//////////////////////////////////////////////////////////////////////////
// Item Accessors
//////////////////////////////////////////////////////////////////////////
ConsoleMethod( GuiListBoxCtrl, setMultipleSelection, void, 3, 3, "listBox.setMultipleSelection([true/false])" )
{
object->setMultipleSelection( dAtob( argv[2] ) );
}
ConsoleMethod( GuiListBoxCtrl, clearItems, void, 2, 2, "clearItems() - Clears all the items in the listbox" )
{
object->clearItems();
}
void GuiListBoxCtrl::clearItems()
{
// Free item list allocated memory
while( mItems.size() )
deleteItem( 0 );
// Free our vector lists
mItems.clear();
mSelectedItems.clear();
}
ConsoleMethod( GuiListBoxCtrl, clearSelection, void, 2, 2, "clearSelection() - sets all currently selected items to unselected" )
{
object->clearSelection();
}
void GuiListBoxCtrl::clearSelection()
{
if( !mSelectedItems.size() )
return;
VectorPtr<LBItem*>::iterator i = mSelectedItems.begin();
for( ; i != mSelectedItems.end(); i++ )
(*i)->isSelected = false;
mSelectedItems.clear();
}
ConsoleMethod( GuiListBoxCtrl, setSelected, void, 3, 4, "setSelected(index, [true]/false) - sets the item at the index specified to selected or not")
{
bool value = true;
if( argc == 4 )
value = dAtob( argv[3] );
if( value == true )
object->addSelection( dAtoi( argv[2] ) );
else
object->removeSelection( dAtoi( argv[2] ) );
}
void GuiListBoxCtrl::removeSelection( S32 index )
{
// Range Check
if( index >= mItems.size() || index < 0 )
{
Con::warnf("GuiListBoxCtrl::removeSelection - index out of range!" );
return;
}
removeSelection( mItems[index], index );
}
void GuiListBoxCtrl::removeSelection( LBItem *item, S32 index )
{
if( !mSelectedItems.size() )
return;
if( !item )
return;
for( S32 i = 0 ; i < mSelectedItems.size(); i++ )
{
if( mSelectedItems[i] == item )
{
mSelectedItems.erase( &mSelectedItems[i] );
item->isSelected = false;
Con::executef(this, 3, "onUnSelect", Con::getIntArg( index ), item->itemText);
return;
}
}
}
void GuiListBoxCtrl::addSelection( S32 index )
{
// Range Check
if( index >= mItems.size() || index < 0 )
{
Con::warnf("GuiListBoxCtrl::addSelection- index out of range!" );
return;
}
addSelection( mItems[index], index );
}
void GuiListBoxCtrl::addSelection( LBItem *item, S32 index )
{
if( !mMultipleSelections )
{
if( !mSelectedItems.empty() )
{
LBItem* selItem = mSelectedItems.front();
if( selItem != item )
clearSelection();
else
return;
}
}
else
{
if( !mSelectedItems.empty() )
{
for( S32 i = 0; i < mSelectedItems.size(); i++ )
{
if( mSelectedItems[ i ] == item )
return;
}
}
}
item->isSelected = true;
mSelectedItems.push_front( item );
Con::executef(this, 3, "onSelect", Con::getIntArg( index ), item->itemText);
}
S32 GuiListBoxCtrl::getItemIndex( LBItem *item )
{
if( mItems.empty() )
return -1;
// Lookup the index of an item in our list, by the pointer to the item
for( S32 i = 0; i < mItems.size(); i++ )
if( mItems[i] == item )
return i;
return -1;
}
ConsoleMethod( GuiListBoxCtrl, getItemCount, S32, 2, 2, "getItemCount() - returns the number of items in the list")
{
return object->getItemCount();
}
S32 GuiListBoxCtrl::getItemCount()
{
return mItems.size();
}
ConsoleMethod( GuiListBoxCtrl, getSelCount, S32, 2, 2, "getSelCount() - returns the number of items currently selected")
{
return object->getSelCount();
}
S32 GuiListBoxCtrl::getSelCount()
{
return mSelectedItems.size();
}
ConsoleMethod( GuiListBoxCtrl, getSelectedItem, S32, 2, 2, "getSelectedItem() - returns the selected items index. "
"If multiple selections exist it returns the first selected item" )
{
return object->getSelectedItem();
}
S32 GuiListBoxCtrl::getSelectedItem()
{
if( mSelectedItems.empty() || mItems.empty() )
return -1;
S32 i = 0;
for( S32 i = 0 ; i < mItems.size(); i++ )
if( mItems[i]->isSelected )
return i;
return -1;
}
ConsoleMethod( GuiListBoxCtrl, getSelectedItems, const char*, 2, 2, "getSelectedItems() - returns a space delimited list "
"of the selected items indexes in the list")
{
S32 selCount = object->getSelCount();
if( selCount == -1 || selCount == 0 )
return StringTable->lookup("-1");
else if( selCount == 1 )
return Con::getIntArg(object->getSelectedItem());
Vector<S32> selItems;
object->getSelectedItems( selItems );
if( selItems.empty() )
return StringTable->lookup("-1");
UTF8 *retBuffer = Con::getReturnBuffer( selItems.size() * 4 );
dMemset( retBuffer, 0, selItems.size() * 4 );
Vector<S32>::iterator i = selItems.begin();
for( ; i != selItems.end(); i++ )
{
UTF8 retFormat[12];
dSprintf( retFormat, 12, "%d ", (*i) );
dStrcat( retBuffer, retFormat );
}
return retBuffer;
}
void GuiListBoxCtrl::getSelectedItems( Vector<S32> &Items )
{
// Clear our return vector
Items.clear();
// If there are no selected items, return an empty vector
if( mSelectedItems.empty() )
return;
for( S32 i = 0; i < mItems.size(); i++ )
if( mItems[i]->isSelected )
Items.push_back( i );
}
ConsoleMethod(GuiListBoxCtrl, findItemText, S32, 3, 4, "listBox.findItemText( myItemText, [?caseSensitive - false] ) - Returns index of item with matching text")
{
bool bCaseSensitive = false;
if( argc == 4 )
bCaseSensitive = dAtob( argv[3] );
return object->findItemText( argv[2], bCaseSensitive );
}
S32 GuiListBoxCtrl::findItemText( StringTableEntry text, bool caseSensitive )
{
// Check Proper Arguments
if( !text || !text[0] || text == StringTable->lookup("") )
{
Con::warnf("GuiListBoxCtrl::findItemText - No Text Specified!");
return -1;
}
// Check Items Exist.
if( mItems.empty() )
return -1;
// Lookup the index of an item in our list, by the pointer to the item
for( S32 i = 0; i < mItems.size(); i++ )
{
// Case Sensitive Compare?
if( caseSensitive && ( dStrcmp( mItems[i]->itemText, text ) == 0 ) )
return i;
else if (!caseSensitive && ( dStricmp( mItems[i]->itemText, text ) == 0 ))
return i;
}
// Not Found!
return -1;
}
ConsoleMethod(GuiListBoxCtrl, setCurSel, void, 3, 3, "setCurSel(index) - sets the currently selected item at the specified index")
{
object->setCurSel( dAtoi( argv[2] ) );
}
void GuiListBoxCtrl::setCurSel( S32 index )
{
// Range Check
if( index >= mItems.size() )
{
Con::warnf("GuiListBoxCtrl::setCurSel - index out of range!" );
return;
}
// If index -1 is specified, we clear the selection
if( index == -1 )
{
mSelectedItems.clear();
return;
}
// Add the selection
addSelection( mItems[ index ], index );
}
ConsoleMethod( GuiListBoxCtrl, setCurSelRange, void, 3, 4, "setCurSelRange(start,[stop]) - sets the current selection range from"
" index start to stop. if no stop is specified it sets from start index to the end of the list")
{
if( argc == 4 )
object->setCurSelRange( dAtoi(argv[2]) , dAtoi( argv[3] ) );
else
object->setCurSelRange( dAtoi(argv[2]), 999999 );
}
void GuiListBoxCtrl::setCurSelRange( S32 start, S32 stop )
{
// Verify Selection Range
if( start < 0 )
start = 0;
else if( start > mItems.size() )
start = mItems.size();
if( stop < 0 )
stop = 0;
else if( stop > mItems.size() )
stop = mItems.size();
S32 iterStart = ( start < stop ) ? start : stop;
S32 iterStop = ( start < stop ) ? stop : start;
for( ; iterStart <= iterStop; iterStart++ )
addSelection( mItems[iterStart], iterStart );
}
ConsoleMethod( GuiListBoxCtrl, addItem, void, 3, 4, "addItem(text, color) - adds an item to the end of the list with an optional color" )
{
if(argc == 3)
{
object->addItem( argv[2] );
} else if(argc == 4)
{
U32 elementCount = GuiListBoxCtrl::getStringElementCount(argv[3]);
if(elementCount == 3)
{
F32 red, green, blue;
red = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 0 ));
green = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 1 ));
blue = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 2 ));
object->addItemWithColor( argv[2], ColorF(red, green, blue) );
} else
{
Con::warnf("GuiListBoxCtrl::addItem() - Invalid number of parameters for the color!");
}
} else
{
Con::warnf("GuiListBoxCtrl::addItem() - Invalid number of parameters!");
}
}
S32 GuiListBoxCtrl::addItem( StringTableEntry text, void *itemData )
{
// This just calls insert item at the end of the list
return insertItem( mItems.size(), text, itemData );
}
S32 GuiListBoxCtrl::addItemWithColor( StringTableEntry text, ColorF color, void *itemData )
{
// This just calls insert item at the end of the list
return insertItemWithColor( mItems.size(), text, color, itemData );
}
ConsoleMethod(GuiListBoxCtrl, setItemColor, void, 4, 4, "(index, color)")
{
U32 elementCount = GuiListBoxCtrl::getStringElementCount(argv[3]);
if(elementCount == 3)
{
F32 red = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 0 ));
F32 green = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 1 ));
F32 blue = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 2 ));
object->setItemColor( dAtoi(argv[2]), ColorF(red, green, blue) );
}
else
Con::warnf("GuiListBoxCtrl::addItem() - Invalid number of parameters for the color!");
}
void GuiListBoxCtrl::setItemColor( S32 index, ColorF color )
{
if ((index >= mItems.size()) || index < 0)
{
Con::warnf("GuiListBoxCtrl::setItemColor - invalid index");
return;
}
LBItem* item = mItems[index];
item->hasColor = true;
item->color = color;
}
ConsoleMethod(GuiListBoxCtrl, clearItemColor, void, 3, 3, "(index)")
{
object->clearItemColor(dAtoi(argv[2]));
}
void GuiListBoxCtrl::clearItemColor( S32 index )
{
if ((index >= mItems.size()) || index < 0)
{
Con::warnf("GuiListBoxCtrl::setItemColor - invalid index");
return;
}
LBItem* item = mItems[index];
item->hasColor = false;
}
ConsoleMethod( GuiListBoxCtrl, insertItem, void, 4, 4, "insertItem( text, index ) - inserts an item into the list at the specified index")
{
object->insertItem( dAtoi( argv[3] ), argv[2] );
}
S32 GuiListBoxCtrl::insertItem( S32 index, StringTableEntry text, void *itemData )
{
// If the index is greater than our list size, insert it at the end
if( index >= mItems.size() )
index = mItems.size();
// Sanity checking
if( !text )
{
Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL string" );
return -1;
}
LBItem *newItem = new LBItem;
if( !newItem )
{
Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
return -1;
}
// Assign item data
newItem->itemText = StringTable->insert(text);
newItem->itemData = itemData;
newItem->isSelected = false;
newItem->hasColor = false;
// Add to list
mItems.insert(&mItems[index], newItem );
// Resize our list to fit our items
updateSize();
// Return our index in list (last)
return index;
}
S32 GuiListBoxCtrl::insertItemWithColor( S32 index, StringTableEntry text, ColorF color, void *itemData )
{
// If the index is greater than our list size, insert it at the end
if( index >= mItems.size() )
index = mItems.size();
// Sanity checking
if( !text )
{
Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL string" );
return -1;
}
if( color == ColorF(-1, -1, -1) )
{
Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL color" );
return -1;
}
LBItem *newItem = new LBItem;
if( !newItem )
{
Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
return -1;
}
// Assign item data
newItem->itemText = StringTable->insert(text);
newItem->itemData = itemData;
newItem->isSelected = false;
newItem->hasColor = true;
newItem->color = color;
// Add to list
mItems.insert(&mItems[index], newItem );
// Resize our list to fit our items
updateSize();
// Return our index in list (last)
return index;
}
ConsoleMethod ( GuiListBoxCtrl, deleteItem, void, 3, 3, "deleteItem(itemIndex)" )
{
object->deleteItem( dAtoi( argv[2] ) );
}
void GuiListBoxCtrl::deleteItem( S32 index )
{
// Range Check
if( index >= mItems.size() || index < 0 )
{
Con::warnf("GuiListBoxCtrl::deleteItem - index out of range!" );
return;
}
// Grab our item
LBItem* item = mItems[ index ];
if( !item )
{
Con::warnf("GuiListBoxCtrl::deleteItem - Bad Item Data!" );
return;
}
// Remove it from the selected list.
if( item->isSelected )
{
for( VectorPtr<LBItem*>::iterator i = mSelectedItems.begin(); i != mSelectedItems.end(); i++ )
{
if( item == *i )
{
mSelectedItems.erase_fast( i );
break;
}
}
}
// Remove it from the list
mItems.erase( &mItems[ index ] );
// Free the memory associated with it
delete item;
}
ConsoleMethod( GuiListBoxCtrl, getItemText, const char*, 3, 3, "getItemText(index) - returns the text of the item at the specified index")
{
return object->getItemText( dAtoi( argv[2] ) );
}
StringTableEntry GuiListBoxCtrl::getItemText( S32 index )
{
// Range Checking
if( index > mItems.size() || index < 0 )
{
Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
return StringTable->lookup("");
}
return mItems[ index ]->itemText;
}
ConsoleMethod( GuiListBoxCtrl, setItemText, void, 4, 4, "setItemText(index, newtext) - sets the items text at the specified index" )
{
object->setItemText( dAtoi( argv[2] ), argv[3] );
}
void GuiListBoxCtrl::setItemText( S32 index, StringTableEntry text )
{
// Sanity Checking
if( !text )
{
Con::warnf("GuiListBoxCtrl::setItemText - Invalid Text Specified!" );
return;
}
// Range Checking
if( index > mItems.size() || index < 0 )
{
Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
return;
}
mItems[ index ]->itemText = StringTable->insert( text );
}
//////////////////////////////////////////////////////////////////////////
// Sizing Functions
//////////////////////////////////////////////////////////////////////////
void GuiListBoxCtrl::updateSize()
{
if( !mProfile )
return;
GFont *font = mProfile->mFont;
GuiScrollCtrl* parent = dynamic_cast<GuiScrollCtrl *>(getParent());
if ( mFitParentWidth && parent )
mItemSize.x = parent->getContentExtent().x;
else
{
// Find the maximum width cell:
S32 maxWidth = 1;
for ( U32 i = 0; i < mItems.size(); i++ )
{
S32 width = font->getStrWidth( mItems[i]->itemText );
if( width > maxWidth )
maxWidth = width;
}
mItemSize.x = maxWidth + 6;
}
mItemSize.y = font->getHeight() + 2;
Point2I newExtent( mItemSize.x, mItemSize.y * mItems.size() );
resize( mBounds.point, newExtent );
}
void GuiListBoxCtrl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
{
Parent::parentResized( oldParentExtent, newParentExtent );
updateSize();
}
//////////////////////////////////////////////////////////////////////////
// Overrides
//////////////////////////////////////////////////////////////////////////
void GuiListBoxCtrl::onRender( Point2I offset, const RectI &updateRect )
{
RectI clipRect(updateRect.point, updateRect.extent);
if( !mProfile )
return;
// Save our original clip rect
RectI oldClipRect = clipRect;
for ( S32 i = 0; i < mItems.size(); i++)
{
S32 colorBoxSize = 0;
ColorI boxColor = ColorI(0, 0, 0);
// Only render visible items
if ((i + 1) * mItemSize.y + offset.y < updateRect.point.y)
continue;
// Break our once we're no longer in visible item range
if( i * mItemSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
break;
// Render color box if needed
if(mItems[i]->hasColor)
{
// Set the size of the color box to be drawn next to the item text
colorBoxSize = 3;
boxColor = ColorI(mItems[i]->color);
// Draw the box first
ColorI black = ColorI(0, 0, 0);
drawBox( Point2I(offset.x + mProfile->mTextOffset.x + colorBoxSize, offset.y + ( i * mItemSize.y ) + 8), colorBoxSize, black, boxColor );
}
RectI itemRect = RectI( offset.x + mProfile->mTextOffset.x + (colorBoxSize * 2), offset.y + ( i * mItemSize.y ), mItemSize.x, mItemSize.y );
// Render our item
onRenderItem( itemRect, mItems[i] );
}
dglSetClipRect( oldClipRect );
}
void GuiListBoxCtrl::onRenderItem( RectI itemRect, LBItem *item )
{
if( item->isSelected )
dglDrawRectFill( itemRect, mProfile->mFillColor );
dglSetBitmapModulation(mProfile->mFontColor);
renderJustifiedText(itemRect.point + Point2I( 2, 0 ), itemRect.extent, item->itemText);
}
void GuiListBoxCtrl::drawBox(const Point2I &box, S32 size, ColorI &outlineColor, ColorI &boxColor)
{
RectI r(box.x - size, box.y - size, 2 * size + 1, 2 * size + 1);
r.inset(1, 1);
dglDrawRectFill(r, boxColor);
r.inset(-1, -1);
dglDrawRect(r, outlineColor);
}
//////////////////////////////////////////////////////////////////////////
// Item Selections
//////////////////////////////////////////////////////////////////////////
void GuiListBoxCtrl::onMouseDown( const GuiEvent &event )
{
Point2I localPoint = globalToLocalCoord(event.mousePoint);
S32 itemHit = ( localPoint.y < 0 ) ? -1 : (S32)mFloor( (F32)localPoint.y / (F32)mItemSize.y );
if ( itemHit >= mItems.size() || itemHit == -1 )
return;
LBItem *hitItem = mItems[ itemHit ];
if ( hitItem == NULL )
return;
// If we're not a multiple selection listbox, we simply select/unselect an item
if( !mMultipleSelections )
{
// No current selection? Just select the cell and move on
S32 selItem = getSelectedItem();
if ( selItem != itemHit && selItem != -1 )
clearSelection();
// Set the current selection
setCurSel( itemHit );
if( itemHit == selItem && event.mouseClickCount == 2 && isMethod("onDoubleClick") )
Con::executef( this, 2, "onDoubleClick" );
// Store the clicked item
mLastClickItem = hitItem;
// Evaluate the console command if we clicked the same item twice
if( selItem == itemHit && event.mouseClickCount > 1 && mAltConsoleCommand[0] )
Con::evaluate( mAltConsoleCommand, false );
return;
}
// Deal with multiple selections
if( event.modifier & SI_CTRL)
{
// Ctrl-Click toggles selection
if( hitItem->isSelected )
{
removeSelection( hitItem, itemHit );
// We return here when we deselect an item because we don't store last clicked when we deselect
return;
}
else
addSelection( hitItem, itemHit );
}
else if( event.modifier & SI_SHIFT )
{
if( !mLastClickItem )
addSelection( hitItem, itemHit );
else
setCurSelRange( getItemIndex( mLastClickItem ), itemHit );
}
else
{
if( getSelCount() != 0 )
{
S32 selItem = getSelectedItem();
if( selItem != -1 && mItems[selItem] != hitItem )
clearSelection();
}
addSelection( hitItem, itemHit );
}
if( hitItem == mLastClickItem && event.mouseClickCount == 2 && isMethod("onDoubleClick") )
Con::executef( this, 2, "onDoubleClick" );
mLastClickItem = hitItem;
}
U32 GuiListBoxCtrl::getStringElementCount( const char* inString )
{
// Non-whitespace chars.
static const char* set = " \t\n";
// End of string.
if ( *inString == 0 )
return 0;
U32 wordCount = 0;
U8 search = 0;
// Search String.
while( *inString )
{
// Get string element.
search = *inString;
// End of string?
if ( search == 0 )
break;
// Move to next element.
inString++;
// Search for seperators.
for( U32 i = 0; set[i]; i++ )
{
// Found one?
if( search == set[i] )
{
// Yes...
search = 0;
break;
}
}
// Found a seperator?
if ( search == 0 )
continue;
// We've found a non-seperator.
wordCount++;
// Search for end of non-seperator.
while( 1 )
{
// Get string element.
search = *inString;
// End of string?
if ( search == 0 )
break;
// Move to next element.
inString++;
// Search for seperators.
for( U32 i = 0; set[i]; i++ )
{
// Found one?
if( search == set[i] )
{
// Yes...
search = 0;
break;
}
}
// Found Seperator?
if ( search == 0 )
break;
}
// End of string?
if ( *inString == 0 )
{
// Bah!
break;
}
}
// We've finished.
return wordCount;
}
//------------------------------------------------------------------------------
// Get String Element.
//------------------------------------------------------------------------------
const char* GuiListBoxCtrl::getStringElement( const char* inString, const U32 index )
{
// Non-whitespace chars.
static const char* set = " \t\n";
U32 wordCount = 0;
U8 search = 0;
const char* pWordStart = NULL;
// End of string?
if ( *inString != 0 )
{
// No, so search string.
while( *inString )
{
// Get string element.
search = *inString;
// End of string?
if ( search == 0 )
break;
// Move to next element.
inString++;
// Search for seperators.
for( U32 i = 0; set[i]; i++ )
{
// Found one?
if( search == set[i] )
{
// Yes...
search = 0;
break;
}
}
// Found a seperator?
if ( search == 0 )
continue;
// Found are word?
if ( wordCount == index )
{
// Yes, so mark it.
pWordStart = inString-1;
}
// We've found a non-seperator.
wordCount++;
// Search for end of non-seperator.
while( 1 )
{
// Get string element.
search = *inString;
// End of string?
if ( search == 0 )
break;
// Move to next element.
inString++;
// Search for seperators.
for( U32 i = 0; set[i]; i++ )
{
// Found one?
if( search == set[i] )
{
// Yes...
search = 0;
break;
}
}
// Found Seperator?
if ( search == 0 )
break;
}
// Have we found our word?
if ( pWordStart )
{
// Yes, so we've got our word...
// Result Buffer.
static char buffer[4096];
// Calculate word length.
const U32 length = inString - pWordStart - ((*inString)?1:0);
// Copy Word.
dStrncpy( buffer, pWordStart, length);
buffer[length] = '\0';
// Return Word.
return buffer;
}
// End of string?
if ( *inString == 0 )
{
// Bah!
break;
}
}
}
// Sanity!
AssertFatal( false, "t2dSceneObject::getStringElement() - Couldn't find specified string element!" );
// Didn't find it
return " ";
}