added everything
This commit is contained in:
996
engine/gui/controls/guiListBoxCtrl.cc
Executable file
996
engine/gui/controls/guiListBoxCtrl.cc
Executable file
@@ -0,0 +1,996 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 " ";
|
||||
}
|
||||
Reference in New Issue
Block a user