123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "gui/guiListBoxCtrl.h"
- #include "gui/guiCanvas.h"
- #include <algorithm>
- #include "guiListBoxCtrl_ScriptBinding.h"
- IMPLEMENT_CONOBJECT(GuiListBoxCtrl);
- GuiListBoxCtrl::GuiListBoxCtrl()
- {
- mItems.clear();
- mSelectedItems.clear();
- mMultipleSelections = true;
- mFitParentWidth = true;
- mItemSize = Point2I(10,20);
- mLastClickItem = NULL;
- mRendersChildren = false;
- mIsContainer = false;
- mActive = true;
- caller = this;
- setField("profile", "GuiListBoxProfile");
- }
- 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;
- }
- void GuiListBoxCtrl::addObject(SimObject *obj)
- {
- AssertWarn(0, "GuiListBoxCtrl::addObject: cannot add children to the GuiListBoxCtrl. It is not a container. Child was not added.");
- removeObject(obj);
- }
- #pragma region ItemAccessors
- void GuiListBoxCtrl::clearItems()
- {
- // Free item list allocated memory
- while( mItems.size() )
- deleteItem( 0 );
- // Free our vector lists
- mItems.clear();
- mSelectedItems.clear();
- }
- void GuiListBoxCtrl::clearSelection()
- {
- if( !mSelectedItems.size() )
- return;
- VectorPtr<LBItem*>::iterator i = mSelectedItems.begin();
- for( ; i != mSelectedItems.end(); i++ )
- (*i)->isSelected = false;
- mSelectedItems.clear();
- if (caller->isMethod("onUnselectAll"))
- {
- Con::executef(caller, 1, "onUnselectAll");
- }
- }
- 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;
- if (caller->isMethod("onUnselect"))
- {
- Con::executef(caller, 4, "onUnselect", Con::getIntArg( index ), item->itemText, Con::getIntArg(item->ID));
- }
- 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 );
- ScrollToIndex(index);
- if(caller->isMethod("onSelect"))
- Con::executef(caller, 4, "onSelect", Con::getIntArg( index ), item->itemText, Con::getIntArg(item->ID));
- }
- 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;
- }
- S32 GuiListBoxCtrl::getItemCount()
- {
- return mItems.size();
- }
- S32 GuiListBoxCtrl::getSelCount()
- {
- return mSelectedItems.size();
- }
- S32 GuiListBoxCtrl::getSelectedItem()
- {
- if( mSelectedItems.empty() || mItems.empty() )
- return -1;
- for( S32 i = 0 ; i < mItems.size(); i++ )
- if( mItems[i]->isSelected )
- return i;
- return -1;
- }
- 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 );
- }
- S32 GuiListBoxCtrl::findItemText( StringTableEntry text, bool caseSensitive )
- {
- // Check Proper Arguments
- if( !text || !text[0] || text == StringTable->EmptyString )
- {
- 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;
- }
- void GuiListBoxCtrl::setSelectionInternal(StringTableEntry text)
- {
- if(text != StringTable->EmptyString)
- {
- S32 index = findItemText(text);
- if (index != -1)
- {
- mSelectedItems.clear();
- LBItem *item = mItems[index];
- item->isSelected = true;
- mSelectedItems.push_front(item);
- }
- }
- }
- 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 )
- {
- for (auto item : mItems)
- {
- item->isSelected = false;
- }
- mSelectedItems.clear();
- return;
- }
- // Add the selection
- addSelection( mItems[ index ], index );
- }
- 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 );
- }
- 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 );
- }
- S32 GuiListBoxCtrl::addItemWithID(StringTableEntry text, S32 ID, void *itemData)
- {
- S32 index = insertItem( mItems.size(), text, itemData);
- setItemID(index, ID);
- return index;
- }
- 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;
- }
- 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;
- }
- void GuiListBoxCtrl::clearAllColors()
- {
- if (!mSelectedItems.size())
- return;
- VectorPtr<LBItem*>::iterator i = mSelectedItems.begin();
- for (; i != mSelectedItems.end(); i++)
- (*i)->hasColor = false;
- }
- ColorF GuiListBoxCtrl::getItemColor(S32 index)
- {
- if ((index >= mItems.size()) || index < 0)
- {
- Con::warnf("GuiListBoxCtrl::getItemColor - invalid index");
- return ColorF(0,0,0,0);
- }
- LBItem* item = mItems[index];
- return item->color;
- }
- bool GuiListBoxCtrl::getItemHasColor(S32 index)
- {
- if ((index >= mItems.size()) || index < 0)
- {
- Con::warnf("GuiListBoxCtrl::getItemHasColor - invalid index");
- return false;
- }
- LBItem* item = mItems[index];
- return item->hasColor;
- }
- void GuiListBoxCtrl::setItemID(S32 index, S32 ID)
- {
- if ((index >= mItems.size()) || index < 0)
- {
- Con::warnf("GuiListBoxCtrl::setItemID - invalid index");
- return;
- }
- LBItem* item = mItems[index];
- item->ID = ID;
- }
- S32 GuiListBoxCtrl::getItemID(S32 index)
- {
- if ((index >= mItems.size()) || index < 0)
- {
- Con::warnf("GuiListBoxCtrl::setItemID - invalid index");
- return 0;
- }
- LBItem* item = mItems[index];
- return item->ID;
- }
- S32 GuiListBoxCtrl::findItemID(S32 ID)
- {
- // 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++)
- {
- if (mItems[i]->ID == ID)
- {
- return i;
- }
- }
- // Not Found!
- return -1;
- }
- void GuiListBoxCtrl::setItemActive(S32 index)
- {
- if ((index >= mItems.size()) || index < 0)
- {
- Con::warnf("GuiListBoxCtrl::setItemActive - invalid index");
- return;
- }
- LBItem* item = mItems[index];
- item->isActive = true;
- }
- void GuiListBoxCtrl::setItemInactive(S32 index)
- {
- if ((index >= mItems.size()) || index < 0)
- {
- Con::warnf("GuiListBoxCtrl::setItemInactive - invalid index");
- return;
- }
- LBItem* item = mItems[index];
- item->isActive = false;
- }
- bool GuiListBoxCtrl::getItemActive(S32 index)
- {
- if ((index >= mItems.size()) || index < 0)
- {
- Con::warnf("GuiListBoxCtrl::getItemActive - invalid index");
- return true;
- }
- LBItem* item = mItems[index];
- return item->isActive;
- }
- 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 = createItem();
- if( !newItem )
- {
- Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
- return -1;
- }
- // Assign item data
- newItem->itemText = StringTable->insert(text, true);
- newItem->isSelected = false;
- newItem->isActive = true;
- newItem->ID = 0;
- newItem->itemData = itemData;
- newItem->hasColor = false;
- // Add to list
- mItems.insert(index);
- mItems[index] = newItem;
- // Resize our list to fit our items
- updateSize();
- // Return our index in list (last)
- return index;
- }
- GuiListBoxCtrl::LBItem* GuiListBoxCtrl::createItem()
- {
- LBItem* newItem = new LBItem;
- if (!newItem)
- {
- return nullptr;
- }
- return newItem;
- }
- S32 GuiListBoxCtrl::insertItemWithColor( S32 index, StringTableEntry text, ColorF color, void *itemData )
- {
- if( color == ColorF(-1, -1, -1) )
- {
- Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL color" );
- return -1;
- }
- index = insertItem(index, text, itemData);
- if(index != -1)
- {
- setItemColor(index, color);
- }
- // Return our index in list (last)
- return index;
- }
- 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;
- }
- StringTableEntry GuiListBoxCtrl::getItemText( S32 index )
- {
- // Range Checking
- if( index > mItems.size() || index < 0 )
- {
- Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
- return StringTable->EmptyString;
- }
-
- return mItems[ index ]->itemText;
- }
- 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 );
- }
- #pragma endregion
- #pragma region Sizing
- void GuiListBoxCtrl::updateSize()
- {
- if( !mProfile || !mProfile->getFont(mFontSizeAdjust))
- return;
- GFont *font = mProfile->getFont(mFontSizeAdjust);
- Point2I contentSize = Point2I(10, font->getHeight() + 2);
- if (!mFitParentWidth)
- {
- // Find the maximum width cell:
- S32 maxWidth = 1;
- for ( U32 i = 0; i < (U32)mItems.size(); i++ )
- {
- S32 width = font->getStrWidth( mItems[i]->itemText );
- if( width > maxWidth )
- maxWidth = width;
- }
- contentSize.x = maxWidth + 6;
- }
- mItemSize = this->getOuterExtent(contentSize, NormalState, mProfile);
- Point2I newExtent = Point2I(mItemSize.x, mItemSize.y * mItems.size());
- //Don't update the extent.x if we are matching our parent's size. We will handle it during rendering.
- if (mFitParentWidth)
- {
- newExtent.x = mBounds.extent.x;
- }
- resize( mBounds.point, newExtent );
- }
- void GuiListBoxCtrl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
- {
- Parent::parentResized( oldParentExtent, newParentExtent );
- updateSize();
- }
- #pragma endregion
- #pragma region Rendering
- void GuiListBoxCtrl::onRender( Point2I offset, const RectI &updateRect )
- {
- RectI clip = dglGetClipRect();
- if (mFitParentWidth && ( mBounds.extent.x != clip.extent.x || mItemSize.x != clip.extent.x))
- {
- mBounds.extent.x = clip.extent.x;
- mItemSize.x = clip.extent.x;
- }
- for ( S32 i = 0; i < mItems.size(); i++)
- {
- // Only render visible items
- if ((i + 1) * mItemSize.y + offset.y < updateRect.point.y)
- continue;
- // Break out once we're no longer in visible item range
- if( i * mItemSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
- break;
- RectI itemRect = RectI( offset.x, offset.y + ( i * mItemSize.y ), mItemSize.x, mItemSize.y );
- // Render our item
- onRenderItem( itemRect, mItems[i] );
- }
- }
- void GuiListBoxCtrl::onRenderItem( RectI &itemRect, LBItem *item )
- {
- Point2I cursorPt = Point2I(0,0);
- GuiCanvas *root = getRoot();
- if (root)
- {
- cursorPt = root->getCursorPos();
- }
- GuiControlState currentState = GuiControlState::NormalState;
- if (!mActive || !item->isActive)
- currentState = GuiControlState::DisabledState;
- else if (item->isSelected)
- currentState = GuiControlState::SelectedState;
- else if (itemRect.pointInRect(cursorPt))
- currentState = GuiControlState::HighlightState;
- RectI ctrlRect = applyMargins(itemRect.point, itemRect.extent, currentState, mProfile);
- if (!ctrlRect.isValidRect())
- {
- return;
- }
- renderUniversalRect(ctrlRect, mProfile, currentState);
- //Render Text
- dglSetBitmapModulation(getFontColor(mProfile, currentState));
- RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, currentState, mProfile);
- RectI contentRect = applyPadding(fillRect.point, fillRect.extent, currentState, mProfile);
- // Render color bullet if needed
- if (item->hasColor)
- {
- RectI drawArea = RectI(contentRect.point.x, contentRect.point.y, contentRect.extent.y, contentRect.extent.y);
- ColorI color = item->color;
- renderColorBullet(drawArea, color, 5);
- contentRect.point.x += contentRect.extent.y;
- contentRect.extent.x -= contentRect.extent.y;
- }
- renderText(contentRect.point, contentRect.extent, item->itemText, mProfile);
- }
- void GuiListBoxCtrl::ScrollToIndex(const S32 targetIndex)
- {
- GuiScrollCtrl* parent = dynamic_cast<GuiScrollCtrl *>(getParent());
- if (parent)
- parent->scrollRectVisible(RectI(0, mItemSize.y * targetIndex, mItemSize.x, mItemSize.y));
- }
- #pragma endregion
- #pragma region InputEvents
- void GuiListBoxCtrl::onTouchDragged(const GuiEvent &event)
- {
- if (!mActive || !mVisible)
- {
- return;
- }
- S32 hitIndex = getHitIndex(event);
- if (hitIndex >= mItems.size() || hitIndex == -1)
- return;
- LBItem *hitItem = mItems[hitIndex];
- if (hitItem == NULL || !hitItem->isActive)
- return;
- if(caller->isMethod("onTouchDragged"))
- {
- Con::executef(caller, 4, "onTouchDragged", Con::getIntArg(hitIndex), hitItem->itemText, Con::getIntArg(hitItem->ID));
- }
- else
- {
- GuiControl* parent = getParent();
- if (parent)
- parent->onTouchDragged(event);
- }
- }
- void GuiListBoxCtrl::onTouchDown( const GuiEvent &event )
- {
- if (!mActive || !mVisible)
- {
- return;
- }
- setFirstResponder();
- S32 hitIndex = getHitIndex(event);
- if ( hitIndex >= mItems.size() || hitIndex == -1 )
- return;
- LBItem *hitItem = mItems[ hitIndex ];
- if ( hitItem == NULL || !hitItem->isActive)
- return;
- handleItemClick(hitItem, hitIndex, event);
- }
- S32 GuiListBoxCtrl::getHitIndex(const GuiEvent& event)
- {
- Point2I localPoint = globalToLocalCoord(event.mousePoint);
- return (localPoint.y < 0) ? -1 : (S32)mFloor((F32)localPoint.y / (F32)mItemSize.y);
- }
- void GuiListBoxCtrl::handleItemClick(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
- {
- if( !mMultipleSelections )
- {
- handleItemClick_SingleSelection(hitItem, hitIndex, event);
- }
- else
- {
- if (!handleItemClick_MultiSelection(hitItem, hitIndex, event))
- {
- return;
- }
- }
- handleItemClick_ClickCallbacks(hitItem, hitIndex, event);
- mLastClickItem = hitItem;
- }
- void GuiListBoxCtrl::handleItemClick_SingleSelection(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
- {
- // No current selection? Just select the cell and move on
- S32 selItem = getSelectedItem();
- if (selItem != hitIndex && selItem != -1)
- clearSelection();
- // Set the current selection
- setCurSel(hitIndex);
- }
- bool GuiListBoxCtrl::handleItemClick_MultiSelection(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
- {
- // Deal with multiple selections
- if (event.modifier & SI_CTRL)
- {
- // Ctrl-Click toggles selection
- if (hitItem->isSelected)
- {
- removeSelection(hitItem, hitIndex);
- // We return here when we deselect an item because we don't store last clicked when we deselect
- return false;
- }
- else
- addSelection(hitItem, hitIndex);
- }
- else if (event.modifier & SI_SHIFT)
- {
- if (!mLastClickItem)
- addSelection(hitItem, hitIndex);
- else
- setCurSelRange(getItemIndex(mLastClickItem), hitIndex);
- }
- else
- {
- if (getSelCount() != 0)
- {
- S32 selItem = getSelectedItem();
- if (selItem != -1 && mItems[selItem] != hitItem)
- clearSelection();
- }
- addSelection(hitItem, hitIndex);
- }
- return true;
- }
- void GuiListBoxCtrl::handleItemClick_ClickCallbacks(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
- {
- if (hitItem == mLastClickItem && event.mouseClickCount == 2)
- {
- if (caller->isMethod("onDoubleClick"))
- Con::executef(caller, 4, "onDoubleClick", Con::getIntArg(hitIndex), hitItem->itemText, Con::getIntArg(hitItem->ID));
- }
- else if (caller->isMethod("onClick"))
- {
- Con::executef(caller, 4, "onClick", Con::getIntArg(hitIndex), hitItem->itemText, Con::getIntArg(hitItem->ID));
- }
- }
- bool GuiListBoxCtrl::onKeyDown(const GuiEvent &event)
- {
- //if this control is a dead end, make sure the event stops here
- if (!mVisible || !mActive || !mAwake || mItems.size() == 0)
- return true;
- S32 index = getSelectedItem();
- switch (event.keyCode)
- {
- case KEY_RETURN:
- if (mAltConsoleCommand[0])
- Con::evaluate(mAltConsoleCommand, false);
- return true;
- case KEY_LEFT:
- case KEY_UP:
- if (index == -1)
- {
- //Select the bottom item
- addSelection(mItems.size() - 1);
- return true;
- }
- else if(index != 0)
- {
- addSelection(index - 1);
- return true;
- }
- break;
- case KEY_DOWN:
- case KEY_RIGHT:
- if (index == -1)
- {
- //Select the top item
- addSelection(0);
- return true;
- }
- else if (index != (mItems.size() - 1))
- {
- addSelection(index + 1);
- return true;
- }
- break;
- case KEY_HOME:
- addSelection(0);
- return true;
- case KEY_END:
- addSelection(mItems.size() - 1);
- return true;
- case KEY_DELETE:
- if (index != -1 && isMethod("onDeleteKey"))
- Con::executef(caller, 4, "onDeleteKey", Con::getIntArg(index), getItemText(index), Con::getIntArg(getItemID(index)));
- return true;
- default:
- return Parent::onKeyDown(event);
- };
- return false;
- }
- #pragma endregion
- #pragma region sorting
- bool GuiListBoxCtrl::LBItem::sIncreasing = true;
- void GuiListBoxCtrl::sortByText(bool increasing)
- {
- if (mItems.size() < 2)
- return;
- LBItem::sIncreasing = increasing;
- std::sort(mItems.begin(), mItems.end(), LBItem::compByText);
- }
- void GuiListBoxCtrl::sortByID(bool increasing)
- {
- if (mItems.size() < 2)
- return;
- LBItem::sIncreasing = increasing;
- std::sort(mItems.begin(), mItems.end(), LBItem::compByID);
- }
- #pragma endregion
|