00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "MyGUI_Precompiled.h"
00024 #include "MyGUI_MultiList.h"
00025 #include "MyGUI_ResourceSkin.h"
00026 #include "MyGUI_Button.h"
00027 #include "MyGUI_StaticImage.h"
00028 #include "MyGUI_List.h"
00029 #include "MyGUI_Gui.h"
00030 #include "MyGUI_WidgetManager.h"
00031
00032 namespace MyGUI
00033 {
00034
00035 MultiList::MultiList() :
00036 mHeightButton(0),
00037 mWidthBar(0),
00038 mButtonMain(nullptr),
00039 mLastMouseFocusIndex(ITEM_NONE),
00040 mSortUp(true),
00041 mSortColumnIndex(ITEM_NONE),
00042 mWidthSeparator(0),
00043 mOffsetButtonSeparator(2),
00044 mItemSelected(ITEM_NONE),
00045 mFrameAdvise(false),
00046 mClient(nullptr)
00047 {
00048 }
00049
00050 void MultiList::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, WidgetPtr _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
00051 {
00052 Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
00053
00054 initialiseWidgetSkin(_info);
00055 }
00056
00057 MultiList::~MultiList()
00058 {
00059 frameAdvise(false);
00060 shutdownWidgetSkin();
00061 }
00062
00063 void MultiList::baseChangeWidgetSkin(ResourceSkin* _info)
00064 {
00065 shutdownWidgetSkin();
00066 Base::baseChangeWidgetSkin(_info);
00067 initialiseWidgetSkin(_info);
00068 }
00069
00070 void MultiList::initialiseWidgetSkin(ResourceSkin* _info)
00071 {
00072
00073 const MapString& properties = _info->getProperties();
00074 if (false == properties.empty()) {
00075 MapString::const_iterator iter = properties.find("SkinButton");
00076 if (iter != properties.end()) mSkinButton = iter->second;
00077 iter = properties.find("HeightButton");
00078 if (iter != properties.end()) mHeightButton = utility::parseInt(iter->second);
00079 if (mHeightButton < 0) mHeightButton = 0;
00080
00081 iter = properties.find("SkinList");
00082 if (iter != properties.end()) mSkinList = iter->second;
00083
00084 iter = properties.find("SkinButtonEmpty");
00085 if (iter != properties.end()) {
00086 mButtonMain = mClient->createWidget<Button>(iter->second,
00087 IntCoord(0, 0, mClient->getWidth(), mHeightButton), Align::Default);
00088 }
00089
00090 iter = properties.find("WidthSeparator");
00091 if (iter != properties.end()) mWidthSeparator = utility::parseInt(iter->second);
00092 iter = properties.find("SkinSeparator");
00093 if (iter != properties.end()) mSkinSeparator = iter->second;
00094 }
00095
00096 for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter) {
00097 if (*(*iter)->_getInternalData<std::string>() == "Client") {
00098 MYGUI_DEBUG_ASSERT( ! mClient, "widget already assigned");
00099 mClient = (*iter);
00100 mWidgetClient = (*iter);
00101 }
00102 }
00103
00104 if (nullptr == mClient) mClient = this;
00105 }
00106
00107 void MultiList::shutdownWidgetSkin()
00108 {
00109 mWidgetClient = nullptr;
00110 mClient = nullptr;
00111 }
00112
00113
00114
00115 void MultiList::insertColumnAt(size_t _column, const UString& _name, int _width, Any _data)
00116 {
00117 MYGUI_ASSERT_RANGE_INSERT(_column, mVectorColumnInfo.size(), "MultiList::insertColumnAt");
00118 if (_column == ITEM_NONE) _column = mVectorColumnInfo.size();
00119
00120
00121 if (false == mVectorColumnInfo.empty())
00122 mVectorColumnInfo.back().list->setScrollVisible(false);
00123 else mSortColumnIndex = 0;
00124
00125 ColumnInfo column;
00126 column.width = _width < 0 ? 0 : _width;
00127
00128 column.list = mClient->createWidget<List>(mSkinList, IntCoord(), Align::Left | Align::VStretch);
00129 column.list->eventListChangePosition = newDelegate(this, &MultiList::notifyListChangePosition);
00130 column.list->eventListMouseItemFocus = newDelegate(this, &MultiList::notifyListChangeFocus);
00131 column.list->eventListChangeScroll = newDelegate(this, &MultiList::notifyListChangeScrollPosition);
00132 column.list->eventListSelectAccept = newDelegate(this, &MultiList::notifyListSelectAccept);
00133
00134 column.button = mClient->createWidget<Button>(mSkinButton, IntCoord(), Align::Default);
00135 column.button->eventMouseButtonClick = newDelegate(this, &MultiList::notifyButtonClick);
00136 column.name = _name;
00137 column.data = _data;
00138
00139
00140 if (false == mVectorColumnInfo.empty()) {
00141 size_t count = mVectorColumnInfo.front().list->getItemCount();
00142 for (size_t pos=0; pos<count; ++pos)
00143 column.list->addItem("");
00144 }
00145
00146 mVectorColumnInfo.insert(mVectorColumnInfo.begin() + _column, column);
00147
00148 updateColumns();
00149
00150
00151 mVectorColumnInfo.back().list->setScrollVisible(true);
00152 }
00153
00154 void MultiList::setColumnNameAt(size_t _column, const UString& _name)
00155 {
00156 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::setColumnNameAt");
00157 mVectorColumnInfo[_column].name = _name;
00158 redrawButtons();
00159 }
00160
00161 void MultiList::setColumnWidthAt(size_t _column, int _width)
00162 {
00163 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::setColumnWidthAt");
00164 mVectorColumnInfo[_column].width = _width < 0 ? 0 : _width;
00165 updateColumns();
00166 }
00167
00168 const UString& MultiList::getColumnNameAt(size_t _column)
00169 {
00170 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::getColumnNameAt");
00171 return mVectorColumnInfo[_column].name;
00172 }
00173
00174 int MultiList::getColumnWidthAt(size_t _column)
00175 {
00176 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::getColumnWidthAt");
00177 return mVectorColumnInfo[_column].width;
00178 }
00179
00180 void MultiList::removeColumnAt(size_t _column)
00181 {
00182 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::removeColumnAt");
00183
00184 ColumnInfo& info = mVectorColumnInfo[_column];
00185
00186 WidgetManager& manager = WidgetManager::getInstance();
00187 manager.destroyWidget(info.button);
00188 manager.destroyWidget(info.list);
00189
00190 mVectorColumnInfo.erase(mVectorColumnInfo.begin() + _column);
00191
00192 if (mVectorColumnInfo.empty()) {
00193 mSortColumnIndex = ITEM_NONE;
00194 mItemSelected = ITEM_NONE;
00195 }
00196 else {
00197 mSortColumnIndex = 0;
00198 mSortUp = true;
00199 sortList();
00200 }
00201
00202 updateColumns();
00203 }
00204
00205 void MultiList::removeAllColumns()
00206 {
00207 WidgetManager& manager = WidgetManager::getInstance();
00208 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00209 manager.destroyWidget((*iter).button);
00210 manager.destroyWidget((*iter).list);
00211 }
00212 mVectorColumnInfo.clear();
00213 mSortColumnIndex = ITEM_NONE;
00214
00215 updateColumns();
00216
00217 mItemSelected = ITEM_NONE;
00218 }
00219
00220 void MultiList::sortByColumn(size_t _column, bool _backward)
00221 {
00222 mSortColumnIndex = _column;
00223 if (_backward) {
00224 mSortUp = !mSortUp;
00225 redrawButtons();
00226
00227 if (mFrameAdvise) sortList();
00228
00229 flipList();
00230 }
00231 else {
00232 mSortUp = true;
00233 redrawButtons();
00234 sortList();
00235 }
00236 }
00237
00238 size_t MultiList::getItemCount()
00239 {
00240 if (mVectorColumnInfo.empty()) return 0;
00241 return mVectorColumnInfo.front().list->getItemCount();
00242 }
00243
00244 void MultiList::removeAllItems()
00245 {
00246 BiIndexBase::removeAllItems();
00247 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00248 (*iter).list->removeAllItems();
00249 }
00250
00251 mItemSelected = ITEM_NONE;
00252 }
00253
00254
00255
00256
00257
00258
00259
00260
00261 void MultiList::updateBackSelected(size_t _index)
00262 {
00263 if (_index == ITEM_NONE) {
00264 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00265 (*iter).list->clearIndexSelected();
00266 }
00267 }
00268 else {
00269
00270 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00271 (*iter).list->setIndexSelected(_index);
00272 }
00273 }
00274 }
00275
00276 void MultiList::setIndexSelected(size_t _index)
00277 {
00278 if (_index == mItemSelected) return;
00279
00280 MYGUI_ASSERT_RANGE(0, mVectorColumnInfo.size(), "MultiList::setIndexSelected");
00281 MYGUI_ASSERT_RANGE_AND_NONE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiList::setIndexSelected");
00282
00283 mItemSelected = _index;
00284 updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
00285 }
00286
00287 void MultiList::setSubItemNameAt(size_t _column, size_t _index, const UString& _name)
00288 {
00289 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::setSubItemAt");
00290 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiList::setSubItemAt");
00291
00292 size_t index = BiIndexBase::convertToBack(_index);
00293 mVectorColumnInfo[_column].list->setItemNameAt(index, _name);
00294
00295
00296 if (_column == mSortColumnIndex) frameAdvise(true);
00297 }
00298
00299 const UString& MultiList::getSubItemNameAt(size_t _column, size_t _index)
00300 {
00301 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::getSubItemNameAt");
00302 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiList::getSubItemNameAt");
00303
00304 size_t index = BiIndexBase::convertToBack(_index);
00305 return mVectorColumnInfo[_column].list->getItemNameAt(index);
00306 }
00307
00308 size_t MultiList::findSubItemWith(size_t _column, const UString& _name)
00309 {
00310 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::findSubItemWith");
00311
00312 size_t index = mVectorColumnInfo[_column].list->findItemIndexWith(_name);
00313 return BiIndexBase::convertToFace(index);
00314 }
00315
00316
00317 void MultiList::updateOnlyEmpty()
00318 {
00319 if (nullptr == mButtonMain) return;
00320
00321 if (mWidthBar >= mClient->getWidth()) mButtonMain->setVisible(false);
00322 else {
00323 mButtonMain->setCoord(mWidthBar, 0, mClient->getWidth()-mWidthBar, mHeightButton);
00324 mButtonMain->setVisible(true);
00325 }
00326 }
00327
00328 void MultiList::notifyListChangePosition(ListPtr _sender, size_t _position)
00329 {
00330 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00331 if (_sender != (*iter).list) (*iter).list->setIndexSelected(_position);
00332 }
00333
00334 updateBackSelected(_position);
00335
00336 mItemSelected = BiIndexBase::convertToFace(_position);
00337
00338
00339 eventListChangePosition(this, mItemSelected);
00340 }
00341
00342 void MultiList::notifyListSelectAccept(ListPtr _sender, size_t _position)
00343 {
00344
00345 eventListSelectAccept(this, BiIndexBase::convertToFace(_position));
00346 }
00347
00348 void MultiList::notifyListChangeFocus(ListPtr _sender, size_t _position)
00349 {
00350 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00351 if (_sender != (*iter).list) {
00352 if (ITEM_NONE != mLastMouseFocusIndex) (*iter).list->_setItemFocus(mLastMouseFocusIndex, false);
00353 if (ITEM_NONE != _position) (*iter).list->_setItemFocus(_position, true);
00354 }
00355 }
00356 mLastMouseFocusIndex = _position;
00357 }
00358
00359 void MultiList::notifyListChangeScrollPosition(ListPtr _sender, size_t _position)
00360 {
00361 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00362 if (_sender != (*iter).list)
00363 (*iter).list->setScrollPosition(_position);
00364 }
00365 }
00366
00367 void MultiList::notifyButtonClick(MyGUI::WidgetPtr _sender)
00368 {
00369 size_t index = *_sender->_getInternalData<size_t>();
00370 sortByColumn(index, index == mSortColumnIndex);
00371 }
00372
00373 void MultiList::redrawButtons()
00374 {
00375 size_t pos = 0;
00376 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00377 if (pos == mSortColumnIndex) {
00378 if (mSortUp) setButtonImageIndex((*iter).button, SORT_UP);
00379 else setButtonImageIndex((*iter).button, SORT_DOWN);
00380 }
00381 else setButtonImageIndex((*iter).button, SORT_NONE);
00382 (*iter).button->setCaption((*iter).name);
00383 pos++;
00384 }
00385 }
00386
00387 void MultiList::setButtonImageIndex(ButtonPtr _button, size_t _index)
00388 {
00389 StaticImagePtr image = _button->getStaticImage();
00390 if ( nullptr == image ) return;
00391 if (image->getItemResource()) {
00392 static const size_t CountIcons = 3;
00393 static const char * IconNames[CountIcons + 1] = {"None", "Up", "Down", ""};
00394 if (_index >= CountIcons) _index = CountIcons;
00395 image->setItemName(IconNames[_index]);
00396 }
00397 else {
00398 image->setItemSelect(_index);
00399 }
00400 }
00401
00402 void MultiList::frameEntered(float _frame)
00403 {
00404 sortList();
00405 }
00406
00407 void MultiList::frameAdvise(bool _advise)
00408 {
00409 if( _advise )
00410 {
00411 if( ! mFrameAdvise )
00412 {
00413 MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate( this, &MultiList::frameEntered );
00414 mFrameAdvise = true;
00415 }
00416 }
00417 else
00418 {
00419 if( mFrameAdvise )
00420 {
00421 MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate( this, &MultiList::frameEntered );
00422 mFrameAdvise = false;
00423 }
00424 }
00425 }
00426
00427 WidgetPtr MultiList::getSeparator(size_t _index)
00428 {
00429 if (!mWidthSeparator || mSkinSeparator.empty()) return nullptr;
00430
00431 if (_index == mVectorColumnInfo.size()-1) return nullptr;
00432
00433 while (_index >= mSeparators.size()) {
00434 WidgetPtr separator = mClient->createWidget<Widget>(mSkinSeparator, IntCoord(), Align::Default);
00435 mSeparators.push_back(separator);
00436 }
00437
00438 return mSeparators[_index];
00439 }
00440
00441 void MultiList::updateColumns()
00442 {
00443 mWidthBar = 0;
00444 size_t index = 0;
00445 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00446 (*iter).list->setCoord(mWidthBar, mHeightButton, (*iter).width, mClient->getHeight() - mHeightButton);
00447 (*iter).button->setCoord(mWidthBar, 0, (*iter).width, mHeightButton);
00448 (*iter).button->_setInternalData(index);
00449
00450 mWidthBar += (*iter).width;
00451
00452
00453 WidgetPtr separator = getSeparator(index);
00454 if (separator) {
00455 separator->setCoord(mWidthBar, 0, mWidthSeparator, mClient->getHeight());
00456 }
00457
00458 mWidthBar += mWidthSeparator;
00459 index++;
00460 }
00461
00462 redrawButtons();
00463 updateOnlyEmpty();
00464 }
00465
00466 void MultiList::flipList()
00467 {
00468 if (ITEM_NONE == mSortColumnIndex) return;
00469
00470 size_t last = mVectorColumnInfo.front().list->getItemCount();
00471 if (0 == last) return;
00472 last --;
00473 size_t first = 0;
00474
00475 while (first < last) {
00476
00477 BiIndexBase::swapItemsBackAt(first, last);
00478 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00479 (*iter).list->swapItemsAt(first, last);
00480 }
00481
00482 first++;
00483 last--;
00484 }
00485
00486 updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
00487 }
00488
00489 bool MultiList::compare(ListPtr _list, size_t _left, size_t _right)
00490 {
00491 bool result = false;
00492 if(mSortUp) std::swap(_left, _right);
00493 if (requestOperatorLess.empty()) result = _list->getItemNameAt(_left) < _list->getItemNameAt(_right);
00494 else requestOperatorLess(this, mSortColumnIndex, _list->getItemNameAt(_left), _list->getItemNameAt(_right), result);
00495 return result;
00496 }
00497
00498 void MultiList::sortList()
00499 {
00500 if (ITEM_NONE == mSortColumnIndex) return;
00501
00502 ListPtr list = mVectorColumnInfo[mSortColumnIndex].list;
00503
00504 size_t count = list->getItemCount();
00505 if (0 == count) return;
00506
00507
00508 int first, last;
00509 for (size_t step = count>>1; step>0 ; step >>= 1) {
00510 for (size_t i=0;i<(count-step);i++)
00511 {
00512 first=i;
00513 while (first>=0)
00514 {
00515 last = first+step;
00516 if (compare(list, first, last))
00517 {
00518 BiIndexBase::swapItemsBackAt(first, last);
00519 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00520 (*iter).list->swapItemsAt(first, last);
00521 }
00522 }
00523 first--;
00524 }
00525 }
00526 }
00527
00528 frameAdvise(false);
00529
00530 updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
00531 }
00532
00533 void MultiList::insertItemAt(size_t _index, const UString& _name, Any _data)
00534 {
00535 MYGUI_ASSERT_RANGE(0, mVectorColumnInfo.size(), "MultiList::insertItemAt");
00536 MYGUI_ASSERT_RANGE_INSERT(_index, mVectorColumnInfo.front().list->getItemCount(), "MultiList::insertItemAt");
00537 if (ITEM_NONE == _index) _index = mVectorColumnInfo.front().list->getItemCount();
00538
00539
00540
00541 if ((mItemSelected != ITEM_NONE) && (_index <= mItemSelected)) mItemSelected ++;
00542
00543 size_t index = BiIndexBase::insertItemAt(_index);
00544
00545
00546 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00547 (*iter).list->insertItemAt(index, "");
00548 }
00549 mVectorColumnInfo.front().list->setItemNameAt(index, _name);
00550 mVectorColumnInfo.front().list->setItemDataAt(index, _data);
00551
00552 frameAdvise(true);
00553 }
00554
00555 void MultiList::removeItemAt(size_t _index)
00556 {
00557 MYGUI_ASSERT_RANGE(0, mVectorColumnInfo.size(), "MultiList::removeItemAt");
00558 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiList::removeItemAt");
00559
00560 size_t index = BiIndexBase::removeItemAt(_index);
00561
00562 for (VectorColumnInfo::iterator iter=mVectorColumnInfo.begin(); iter!=mVectorColumnInfo.end(); ++iter) {
00563 (*iter).list->removeItemAt(index);
00564 }
00565
00566
00567 size_t count = mVectorColumnInfo.begin()->list->getItemCount();
00568 if (count == 0) mItemSelected = ITEM_NONE;
00569 else if (mItemSelected != ITEM_NONE) {
00570 if (_index < mItemSelected) mItemSelected --;
00571 else if ((_index == mItemSelected) && (mItemSelected == count)) mItemSelected --;
00572 }
00573 updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
00574 }
00575
00576 void MultiList::swapItemsAt(size_t _index1, size_t _index2)
00577 {
00578 MYGUI_ASSERT_RANGE(0, mVectorColumnInfo.size(), "MultiList::removeItemAt");
00579 MYGUI_ASSERT_RANGE(_index1, mVectorColumnInfo.begin()->list->getItemCount(), "MultiList::swapItemsAt");
00580 MYGUI_ASSERT_RANGE(_index2, mVectorColumnInfo.begin()->list->getItemCount(), "MultiList::swapItemsAt");
00581
00582
00583 BiIndexBase::swapItemsFaceAt(_index1, _index2);
00584
00585
00586
00587 }
00588
00589 void MultiList::setColumnDataAt(size_t _index, Any _data)
00590 {
00591 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.size(), "MultiList::setColumnDataAt");
00592 mVectorColumnInfo[_index].data = _data;
00593 }
00594
00595 void MultiList::setSubItemDataAt(size_t _column, size_t _index, Any _data)
00596 {
00597 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiList::setSubItemDataAt");
00598 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiList::setSubItemDataAt");
00599
00600 size_t index = BiIndexBase::convertToBack(_index);
00601 mVectorColumnInfo[_column].list->setItemDataAt(index, _data);
00602 }
00603
00604 }