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