MyGUI  3.2.1
MyGUI_MultiListBox.cpp
Go to the documentation of this file.
00001 /*
00002  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
00003  * Distributed under the MIT License
00004  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
00005  */
00006 
00007 #include "MyGUI_Precompiled.h"
00008 #include "MyGUI_MultiListBox.h"
00009 #include "MyGUI_MultiListItem.h"
00010 #include "MyGUI_ResourceSkin.h"
00011 #include "MyGUI_Button.h"
00012 #include "MyGUI_ImageBox.h"
00013 #include "MyGUI_ListBox.h"
00014 #include "MyGUI_Gui.h"
00015 #include "MyGUI_WidgetManager.h"
00016 
00017 namespace MyGUI
00018 {
00019 
00020     MultiListBox::MultiListBox() :
00021         mHeightButton(0),
00022         mWidthBar(0),
00023         mWidgetEmpty(nullptr),
00024         mLastMouseFocusIndex(ITEM_NONE),
00025         mSortUp(true),
00026         mSortColumnIndex(ITEM_NONE),
00027         mWidthSeparator(0),
00028         mItemSelected(ITEM_NONE),
00029         mFrameAdvise(false),
00030         mClient(nullptr),
00031         mHeaderPlace(nullptr)
00032     {
00033     }
00034 
00035     void MultiListBox::initialiseOverride()
00036     {
00037         Base::initialiseOverride();
00038 
00039         std::string skinButtonEmpty;
00040 
00041         if (isUserString("SkinButton"))
00042             mSkinButton = getUserString("SkinButton");
00043 
00044         if (isUserString("SkinList"))
00045             mSkinList = getUserString("SkinList");
00046 
00047         if (isUserString("SkinSeparator"))
00048             mSkinSeparator = getUserString("SkinSeparator");
00049 
00050         if (isUserString("WidthSeparator"))
00051             mWidthSeparator = utility::parseValue<int>(getUserString("WidthSeparator"));
00052 
00053         // OBSOLETE
00054         if (isUserString("HeightButton"))
00055             mHeightButton = utility::parseValue<int>(getUserString("HeightButton"));
00056         if (mHeightButton < 0)
00057             mHeightButton = 0;
00058 
00060         assignWidget(mHeaderPlace, "HeaderPlace");
00061 
00063         assignWidget(mClient, "Client");
00064         if (mClient != nullptr)
00065             setWidgetClient(mClient);
00066 
00067         if (nullptr == mClient)
00068             mClient = this;
00069 
00071         assignWidget(mWidgetEmpty, "Empty");
00072 
00073         if (mWidgetEmpty == nullptr)
00074         {
00075             if (isUserString("SkinButtonEmpty"))
00076                 skinButtonEmpty = getUserString("SkinButtonEmpty");
00077 
00078             if (!skinButtonEmpty.empty())
00079                 mWidgetEmpty = mClient->createWidget<Widget>(skinButtonEmpty, IntCoord(0, 0, mClient->getWidth(), getButtonHeight()), Align::Default);
00080         }
00081 
00082         if (getUpdateByResize())
00083             updateColumns();
00084     }
00085 
00086     void MultiListBox::shutdownOverride()
00087     {
00088         mClient = nullptr;
00089 
00090         Base::shutdownOverride();
00091     }
00092 
00093     void MultiListBox::setColumnNameAt(size_t _column, const UString& _name)
00094     {
00095         MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::setColumnNameAt");
00096         mVectorColumnInfo[_column].name = _name;
00097         // обновляем кэпшен сначала
00098         redrawButtons();
00099         updateColumns();
00100     }
00101 
00102     void MultiListBox::setColumnWidthAt(size_t _column, int _width)
00103     {
00104         MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::setColumnWidthAt");
00105         mVectorColumnInfo[_column].width = _width;
00106         updateColumns();
00107     }
00108 
00109     const UString& MultiListBox::getColumnNameAt(size_t _column)
00110     {
00111         MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::getColumnNameAt");
00112         return mVectorColumnInfo[_column].name;
00113     }
00114 
00115     int MultiListBox::getColumnWidthAt(size_t _column)
00116     {
00117         MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::getColumnWidthAt");
00118         return mVectorColumnInfo[_column].width;
00119     }
00120 
00121     void MultiListBox::removeAllColumns()
00122     {
00123         while (!mVectorColumnInfo.empty())
00124             removeColumnAt(0);
00125     }
00126 
00127     void MultiListBox::sortByColumn(size_t _column, bool _backward)
00128     {
00129         mSortColumnIndex = _column;
00130         if (_backward)
00131         {
00132             mSortUp = !mSortUp;
00133             redrawButtons();
00134             // если было недосортированно то сортируем
00135             if (mFrameAdvise)
00136                 sortList();
00137 
00138             flipList();
00139         }
00140         else
00141         {
00142             mSortUp = true;
00143             redrawButtons();
00144             sortList();
00145         }
00146     }
00147 
00148     size_t MultiListBox::getItemCount() const
00149     {
00150         if (mVectorColumnInfo.empty())
00151             return 0;
00152         return mVectorColumnInfo.front().list->getItemCount();
00153     }
00154 
00155     void MultiListBox::removeAllItems()
00156     {
00157         BiIndexBase::removeAllItems();
00158         for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00159         {
00160             (*iter).list->removeAllItems();
00161         }
00162 
00163         mItemSelected = ITEM_NONE;
00164     }
00165 
00166     void MultiListBox::updateBackSelected(size_t _index)
00167     {
00168         if (_index == ITEM_NONE)
00169         {
00170             for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00171             {
00172                 (*iter).list->clearIndexSelected();
00173             }
00174         }
00175         else
00176         {
00177             for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00178             {
00179                 (*iter).list->setIndexSelected(_index);
00180             }
00181         }
00182     }
00183 
00184     void MultiListBox::setIndexSelected(size_t _index)
00185     {
00186         if (_index == mItemSelected)
00187             return;
00188 
00189         MYGUI_ASSERT(!mVectorColumnInfo.empty(), "MultiListBox::setIndexSelected");
00190         MYGUI_ASSERT_RANGE_AND_NONE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::setIndexSelected");
00191 
00192         mItemSelected = _index;
00193         updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
00194     }
00195 
00196     void MultiListBox::setSubItemNameAt(size_t _column, size_t _index, const UString& _name)
00197     {
00198         MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::setSubItemAt");
00199 
00200         size_t index = BiIndexBase::convertToBack(_index);
00201         getSubItemAt(_column)->setItemNameAt(index, _name);
00202 
00203         // если мы попортили список с активным сортом, надо пересчитывать
00204         if (_column == mSortColumnIndex)
00205             frameAdvise(true);
00206     }
00207 
00208     const UString& MultiListBox::getSubItemNameAt(size_t _column, size_t _index)
00209     {
00210         MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::getSubItemNameAt");
00211 
00212         size_t index = BiIndexBase::convertToBack(_index);
00213         return getSubItemAt(_column)->getItemNameAt(index);
00214     }
00215 
00216     size_t MultiListBox::findSubItemWith(size_t _column, const UString& _name)
00217     {
00218         size_t index = getSubItemAt(_column)->findItemIndexWith(_name);
00219         return BiIndexBase::convertToFace(index);
00220     }
00221 
00222     int MultiListBox::getButtonHeight() const
00223     {
00224         if (mHeaderPlace != nullptr)
00225             return mHeaderPlace->getHeight();
00226         return mHeightButton;
00227     }
00228 
00229     void MultiListBox::updateOnlyEmpty()
00230     {
00231         if (nullptr == mWidgetEmpty)
00232             return;
00233 
00234         // кнопка, для заполнения пустоты
00235         if (mWidthBar >= mClient->getWidth())
00236             mWidgetEmpty->setVisible(false);
00237         else
00238         {
00239             mWidgetEmpty->setCoord(mWidthBar, 0, mClient->getWidth() - mWidthBar, getButtonHeight());
00240             mWidgetEmpty->setVisible(true);
00241         }
00242     }
00243 
00244     void MultiListBox::notifyListChangePosition(ListBox* _sender, size_t _position)
00245     {
00246         for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00247         {
00248             if (_sender != (*iter).list)
00249                 (*iter).list->setIndexSelected(_position);
00250         }
00251 
00252         updateBackSelected(_position);
00253 
00254         mItemSelected = BiIndexBase::convertToFace(_position);
00255 
00256         // наш евент
00257         eventListChangePosition(this, mItemSelected);
00258     }
00259 
00260     void MultiListBox::notifyListSelectAccept(ListBox* _sender, size_t _position)
00261     {
00262         // наш евент
00263         eventListSelectAccept(this, BiIndexBase::convertToFace(_position));
00264     }
00265 
00266     void MultiListBox::notifyListChangeFocus(ListBox* _sender, size_t _position)
00267     {
00268         for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00269         {
00270             if (_sender != (*iter).list)
00271             {
00272                 if (ITEM_NONE != mLastMouseFocusIndex)
00273                     (*iter).list->_setItemFocus(mLastMouseFocusIndex, false);
00274                 if (ITEM_NONE != _position)
00275                     (*iter).list->_setItemFocus(_position, true);
00276             }
00277         }
00278         mLastMouseFocusIndex = _position;
00279     }
00280 
00281     void MultiListBox::notifyListChangeScrollPosition(ListBox* _sender, size_t _position)
00282     {
00283         for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00284         {
00285             if (_sender != (*iter).list)
00286                 (*iter).list->setScrollPosition(_position);
00287         }
00288     }
00289 
00290     void MultiListBox::notifyButtonClick(MyGUI::Widget* _sender)
00291     {
00292         size_t index = *_sender->_getInternalData<size_t>();
00293         sortByColumn(index, index == mSortColumnIndex);
00294     }
00295 
00296     void MultiListBox::redrawButtons()
00297     {
00298         size_t pos = 0;
00299         for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00300         {
00301             if (pos == mSortColumnIndex)
00302             {
00303                 if (mSortUp)
00304                     (*iter).button->setImageName("Up");
00305                 else
00306                     (*iter).button->setImageName("Down");
00307             }
00308             else
00309                 (*iter).button->setImageName("None");
00310 
00311             (*iter).button->setCaption((*iter).name);
00312             pos++;
00313         }
00314     }
00315 
00316     void MultiListBox::frameEntered(float _frame)
00317     {
00318         sortList();
00319     }
00320 
00321     void MultiListBox::frameAdvise(bool _advise)
00322     {
00323         if (_advise)
00324         {
00325             if (!mFrameAdvise)
00326             {
00327                 MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate( this, &MultiListBox::frameEntered );
00328                 mFrameAdvise = true;
00329             }
00330         }
00331         else
00332         {
00333             if (mFrameAdvise)
00334             {
00335                 MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate( this, &MultiListBox::frameEntered );
00336                 mFrameAdvise = false;
00337             }
00338         }
00339     }
00340 
00341     Widget* MultiListBox::getSeparator(size_t _index)
00342     {
00343         if (!mWidthSeparator || mSkinSeparator.empty())
00344             return nullptr;
00345         // последний столбик
00346         if (_index == mVectorColumnInfo.size() - 1)
00347             return nullptr;
00348 
00349         while (_index >= mSeparators.size())
00350         {
00351             Widget* separator = mClient->createWidget<Widget>(mSkinSeparator, IntCoord(), Align::Default);
00352             mSeparators.push_back(separator);
00353         }
00354 
00355         return mSeparators[_index];
00356     }
00357 
00358     void MultiListBox::flipList()
00359     {
00360         if (ITEM_NONE == mSortColumnIndex)
00361             return;
00362 
00363         size_t last = mVectorColumnInfo.front().list->getItemCount();
00364         if (0 == last)
00365             return;
00366         last --;
00367         size_t first = 0;
00368 
00369         while (first < last)
00370         {
00371             BiIndexBase::swapItemsBackAt(first, last);
00372             for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00373             {
00374                 (*iter).list->swapItemsAt(first, last);
00375             }
00376 
00377             first++;
00378             last--;
00379         }
00380 
00381         updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
00382     }
00383 
00384     bool MultiListBox::compare(ListBox* _list, size_t _left, size_t _right)
00385     {
00386         bool result = false;
00387         if (mSortUp)
00388             std::swap(_left, _right);
00389         if (requestOperatorLess.empty())
00390             result = _list->getItemNameAt(_left) < _list->getItemNameAt(_right);
00391         else
00392             requestOperatorLess(this, mSortColumnIndex, _list->getItemNameAt(_left), _list->getItemNameAt(_right), result);
00393         return result;
00394     }
00395 
00396     void MultiListBox::sortList()
00397     {
00398         if (ITEM_NONE == mSortColumnIndex)
00399             return;
00400 
00401         ListBox* list = mVectorColumnInfo[mSortColumnIndex].list;
00402 
00403         size_t count = list->getItemCount();
00404         if (0 == count)
00405             return;
00406 
00407         // shell sort
00408         int first;
00409         size_t last;
00410         for (size_t step = count >> 1; step > 0 ; step >>= 1)
00411         {
00412             for (size_t i = 0; i < (count - step); i++)
00413             {
00414                 first = (int)i;
00415                 while (first >= 0)
00416                 {
00417                     last = first + step;
00418                     if (compare(list, first, last))
00419                     {
00420                         BiIndexBase::swapItemsBackAt(first, last);
00421                         for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00422                         {
00423                             (*iter).list->swapItemsAt(first, last);
00424                         }
00425                     }
00426                     first--;
00427                 }
00428             }
00429         }
00430 
00431         frameAdvise(false);
00432 
00433         updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
00434     }
00435 
00436     void MultiListBox::insertItemAt(size_t _index, const UString& _name, Any _data)
00437     {
00438         MYGUI_ASSERT(!mVectorColumnInfo.empty(), "MultiListBox::insertItemAt");
00439         MYGUI_ASSERT_RANGE_INSERT(_index, mVectorColumnInfo.front().list->getItemCount(), "MultiListBox::insertItemAt");
00440         if (ITEM_NONE == _index)
00441             _index = mVectorColumnInfo.front().list->getItemCount();
00442 
00443         // если надо, то меняем выделенный элемент
00444         // при сортировке, обновится
00445         if ((mItemSelected != ITEM_NONE) && (_index <= mItemSelected))
00446             mItemSelected ++;
00447 
00448         size_t index = BiIndexBase::insertItemAt(_index);
00449 
00450         // вставляем во все поля пустые, а потом присваиваем первому
00451         for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00452         {
00453             (*iter).list->insertItemAt(index, "");
00454         }
00455         mVectorColumnInfo.front().list->setItemNameAt(index, _name);
00456         mVectorColumnInfo.front().list->setItemDataAt(index, _data);
00457 
00458         frameAdvise(true);
00459     }
00460 
00461     void MultiListBox::removeItemAt(size_t _index)
00462     {
00463         MYGUI_ASSERT(!mVectorColumnInfo.empty(), "MultiListBox::removeItemAt");
00464         MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::removeItemAt");
00465 
00466         size_t index = BiIndexBase::removeItemAt(_index);
00467 
00468         for (VectorColumnInfo::iterator iter = mVectorColumnInfo.begin(); iter != mVectorColumnInfo.end(); ++iter)
00469         {
00470             (*iter).list->removeItemAt(index);
00471         }
00472 
00473         // если надо, то меняем выделенный элемент
00474         size_t count = mVectorColumnInfo.begin()->list->getItemCount();
00475         if (count == 0)
00476             mItemSelected = ITEM_NONE;
00477         else if (mItemSelected != ITEM_NONE)
00478         {
00479             if (_index < mItemSelected)
00480                 mItemSelected --;
00481             else if ((_index == mItemSelected) && (mItemSelected == count))
00482                 mItemSelected --;
00483         }
00484         updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
00485     }
00486 
00487     void MultiListBox::swapItemsAt(size_t _index1, size_t _index2)
00488     {
00489         MYGUI_ASSERT(!mVectorColumnInfo.empty(), "MultiListBox::removeItemAt");
00490         MYGUI_ASSERT_RANGE(_index1, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::swapItemsAt");
00491         MYGUI_ASSERT_RANGE(_index2, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::swapItemsAt");
00492 
00493         // при сортированном, меняем только индексы
00494         BiIndexBase::swapItemsFaceAt(_index1, _index2);
00495 
00496         // при несортированном, нужно наоборот, поменять только данные
00497         // FIXME
00498     }
00499 
00500     void MultiListBox::setColumnDataAt(size_t _index, Any _data)
00501     {
00502         MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.size(), "MultiListBox::setColumnDataAt");
00503         mVectorColumnInfo[_index].data = _data;
00504     }
00505 
00506     void MultiListBox::setSubItemDataAt(size_t _column, size_t _index, Any _data)
00507     {
00508         MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::setSubItemDataAt");
00509 
00510         size_t index = BiIndexBase::convertToBack(_index);
00511         getSubItemAt(_column)->setItemDataAt(index, _data);
00512     }
00513 
00514     size_t MultiListBox::getColumnCount() const
00515     {
00516         return mVectorColumnInfo.size();
00517     }
00518 
00519     void MultiListBox::addColumn(const UString& _name, int _width, Any _data)
00520     {
00521         insertColumnAt(ITEM_NONE, _name, _width, _data);
00522     }
00523 
00524     void MultiListBox::clearColumnDataAt(size_t _index)
00525     {
00526         setColumnDataAt(_index, Any::Null);
00527     }
00528 
00529     void MultiListBox::addItem(const UString& _name, Any _data)
00530     {
00531         insertItemAt(ITEM_NONE, _name, _data);
00532     }
00533 
00534     void MultiListBox::setItemNameAt(size_t _index, const UString& _name)
00535     {
00536         setSubItemNameAt(0, _index, _name);
00537     }
00538 
00539     const UString& MultiListBox::getItemNameAt(size_t _index)
00540     {
00541         return getSubItemNameAt(0, _index);
00542     }
00543 
00544     size_t MultiListBox::getIndexSelected() const
00545     {
00546         return mItemSelected;
00547     }
00548 
00549     void MultiListBox::clearIndexSelected()
00550     {
00551         setIndexSelected(ITEM_NONE);
00552     }
00553 
00554     void MultiListBox::setItemDataAt(size_t _index, Any _data)
00555     {
00556         setSubItemDataAt(0, _index, _data);
00557     }
00558 
00559     void MultiListBox::clearItemDataAt(size_t _index)
00560     {
00561         setItemDataAt(_index, Any::Null);
00562     }
00563 
00564     void MultiListBox::clearSubItemDataAt(size_t _column, size_t _index)
00565     {
00566         setSubItemDataAt(_column, _index, Any::Null);
00567     }
00568 
00569     ListBox* MultiListBox::getSubItemAt(size_t _column)
00570     {
00571         MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::getSubItemAt");
00572         return mVectorColumnInfo[_column].list;
00573     }
00574 
00575     size_t MultiListBox::_getItemCount()
00576     {
00577         return getColumnCount();
00578     }
00579 
00580     void MultiListBox::_addItem(const MyGUI::UString& _name)
00581     {
00582         addColumn(_name);
00583         setColumnResizingPolicyAt(getColumnCount() - 1, ResizingPolicy::Auto);
00584     }
00585 
00586     void MultiListBox::_removeItemAt(size_t _index)
00587     {
00588         removeColumnAt(_index);
00589     }
00590 
00591     void MultiListBox::_setItemNameAt(size_t _index, const UString& _name)
00592     {
00593         setColumnNameAt(_index, _name);
00594     }
00595 
00596     const UString& MultiListBox::_getItemNameAt(size_t _index)
00597     {
00598         return getColumnNameAt(_index);
00599     }
00600 
00601     void MultiListBox::insertColumnAt(size_t _column, const UString& _name, int _width, Any _data)
00602     {
00603         MYGUI_ASSERT_RANGE_INSERT(_column, mVectorColumnInfo.size(), "MultiListBox::insertColumnAt");
00604         if (_column == ITEM_NONE)
00605             _column = mVectorColumnInfo.size();
00606 
00607         createWidget<MultiListItem>("", IntCoord(), Align::Default);
00608 
00609         mVectorColumnInfo.back().width = _width;
00610         mVectorColumnInfo.back().sizeType = ResizingPolicy::Fixed;
00611         mVectorColumnInfo.back().name = _name;
00612         mVectorColumnInfo.back().data = _data;
00613         mVectorColumnInfo.back().button->setCaption(_name);
00614 
00615         if (_column == (mVectorColumnInfo.size() - 1))
00616         {
00617             updateColumns();
00618 
00619             mVectorColumnInfo.back().list->setScrollVisible(true);
00620         }
00621         else
00622         {
00623             _swapColumnsAt(_column, mVectorColumnInfo.size() - 1);
00624         }
00625     }
00626 
00627     void MultiListBox::removeColumnAt(size_t _column)
00628     {
00629         MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::removeColumnAt");
00630 
00631         ColumnInfo& info = mVectorColumnInfo[_column];
00632 
00633         WidgetManager::getInstance().destroyWidget(info.item);
00634     }
00635 
00636     void MultiListBox::swapColumnsAt(size_t _index1, size_t _index2)
00637     {
00638         MYGUI_ASSERT_RANGE(_index1, mVectorColumnInfo.size(), "MultiListBox::swapColumnsAt");
00639         MYGUI_ASSERT_RANGE(_index2, mVectorColumnInfo.size(), "MultiListBox::swapColumnsAt");
00640 
00641         _swapColumnsAt(_index1, _index2);
00642     }
00643 
00644     void MultiListBox::_swapColumnsAt(size_t _index1, size_t _index2)
00645     {
00646         if (_index1 == _index2)
00647             return;
00648 
00649         mVectorColumnInfo[_index1].list->setScrollVisible(false);
00650         mVectorColumnInfo[_index2].list->setScrollVisible(false);
00651 
00652         std::swap(mVectorColumnInfo[_index1], mVectorColumnInfo[_index2]);
00653 
00654         updateColumns();
00655 
00656         mVectorColumnInfo.back().list->setScrollVisible(true);
00657     }
00658 
00659     void MultiListBox::onWidgetCreated(Widget* _widget)
00660     {
00661         Base::onWidgetCreated(_widget);
00662 
00663         MultiListItem* child = _widget->castType<MultiListItem>(false);
00664         if (child != nullptr)
00665         {
00666             _wrapItem(child);
00667         }
00668     }
00669 
00670     void MultiListBox::onWidgetDestroy(Widget* _widget)
00671     {
00672         Base::onWidgetDestroy(_widget);
00673 
00674         MultiListItem* child = _widget->castType<MultiListItem>(false);
00675         if (child != nullptr)
00676         {
00677             _unwrapItem(child);
00678         }
00679         else
00680         {
00681             for (VectorColumnInfo::iterator item = mVectorColumnInfo.begin(); item != mVectorColumnInfo.end(); ++item)
00682             {
00683                 if ((*item).button == _widget)
00684                     (*item).button = nullptr;
00685             }
00686         }
00687     }
00688 
00689     void MultiListBox::_wrapItem(MultiListItem* _item)
00690     {
00691         // скрываем у крайнего скролл
00692         if (!mVectorColumnInfo.empty())
00693             mVectorColumnInfo.back().list->setScrollVisible(false);
00694         else
00695             mSortColumnIndex = ITEM_NONE;
00696 
00697         ColumnInfo column;
00698         column.width = 0;
00699         column.sizeType = ResizingPolicy::Auto;
00700 
00701         column.item = _item;
00702         column.list = _item->createWidget<ListBox>(mSkinList, IntCoord(0, 0, _item->getWidth(), _item->getHeight()), Align::Stretch);
00703         column.list->eventListChangePosition += newDelegate(this, &MultiListBox::notifyListChangePosition);
00704         column.list->eventListMouseItemFocus += newDelegate(this, &MultiListBox::notifyListChangeFocus);
00705         column.list->eventListChangeScroll += newDelegate(this, &MultiListBox::notifyListChangeScrollPosition);
00706         column.list->eventListSelectAccept += newDelegate(this, &MultiListBox::notifyListSelectAccept);
00707 
00708         if (mHeaderPlace != nullptr)
00709             column.button = mHeaderPlace->createWidget<Button>(mSkinButton, IntCoord(), Align::Default);
00710         else
00711             column.button = mClient->createWidget<Button>(mSkinButton, IntCoord(), Align::Default);
00712 
00713         column.button->eventMouseButtonClick += newDelegate(this, &MultiListBox::notifyButtonClick);
00714 
00715         // если уже были столбики, то делаем то же колличество полей
00716         if (!mVectorColumnInfo.empty())
00717         {
00718             size_t count = mVectorColumnInfo.front().list->getItemCount();
00719             for (size_t pos = 0; pos < count; ++pos)
00720                 column.list->addItem("");
00721         }
00722 
00723         mVectorColumnInfo.push_back(column);
00724 
00725         updateColumns();
00726 
00727         // показываем скролл нового крайнего
00728         mVectorColumnInfo.back().list->setScrollVisible(true);
00729     }
00730 
00731     void MultiListBox::_unwrapItem(MultiListItem* _item)
00732     {
00733         for (VectorColumnInfo::iterator item = mVectorColumnInfo.begin(); item != mVectorColumnInfo.end(); ++item)
00734         {
00735             if ((*item).item == _item)
00736             {
00737                 if ((*item).button != nullptr)
00738                     WidgetManager::getInstance().destroyWidget((*item).button);
00739 
00740                 mVectorColumnInfo.erase(item);
00741                 break;
00742             }
00743         }
00744 
00745         if (mVectorColumnInfo.empty())
00746         {
00747             mSortColumnIndex = ITEM_NONE;
00748             mItemSelected = ITEM_NONE;
00749         }
00750         else
00751         {
00752             mSortColumnIndex = ITEM_NONE;
00753             mSortUp = true;
00754             sortList();
00755         }
00756 
00757         updateColumns();
00758 
00759         if (!mVectorColumnInfo.empty())
00760             mVectorColumnInfo.back().list->setScrollVisible(true);
00761     }
00762 
00763     Widget* MultiListBox::_getItemAt(size_t _index)
00764     {
00765         MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.size(), "MultiListBox::_getItemAt");
00766         return mVectorColumnInfo[_index].item;
00767     }
00768 
00769     void MultiListBox::setColumnName(MultiListItem* _item, const UString& _name)
00770     {
00771         setColumnNameAt(getColumnIndex(_item), _name);
00772     }
00773 
00774     const UString& MultiListBox::getColumnName(MultiListItem* _item)
00775     {
00776         return getColumnNameAt(getColumnIndex(_item));
00777     }
00778 
00779     size_t MultiListBox::getColumnIndex(MultiListItem* _item)
00780     {
00781         for (size_t index = 0; index < mVectorColumnInfo.size(); ++ index)
00782         {
00783             if (mVectorColumnInfo[index].item == _item)
00784                 return index;
00785         }
00786 
00787         return ITEM_NONE;
00788     }
00789 
00790     void MultiListBox::setColumnResizingPolicy(MultiListItem* _item, ResizingPolicy _value)
00791     {
00792         setColumnResizingPolicyAt(getColumnIndex(_item), _value);
00793     }
00794 
00795     void MultiListBox::setColumnResizingPolicyAt(size_t _index, ResizingPolicy _value)
00796     {
00797         MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.size(), "MultiListBox::setColumnWidthAt");
00798         mVectorColumnInfo[_index].sizeType = _value;
00799         updateColumns();
00800     }
00801 
00802     void MultiListBox::setColumnWidth(MultiListItem* _item, int _width)
00803     {
00804         setColumnWidthAt(getColumnIndex(_item), _width);
00805     }
00806 
00807     void MultiListBox::setPosition(const IntPoint& _point)
00808     {
00809         Base::setPosition(_point);
00810     }
00811 
00812     void MultiListBox::setSize(const IntSize& _size)
00813     {
00814         Base::setSize(_size);
00815 
00816         if (getUpdateByResize())
00817             updateColumns();
00818     }
00819 
00820     void MultiListBox::setCoord(const IntCoord& _coord)
00821     {
00822         Base::setCoord(_coord);
00823 
00824         if (getUpdateByResize())
00825             updateColumns();
00826     }
00827 
00828     void MultiListBox::setPosition(int _left, int _top)
00829     {
00830         setPosition(IntPoint(_left, _top));
00831     }
00832 
00833     void MultiListBox::setSize(int _width, int _height)
00834     {
00835         setSize(IntSize(_width, _height));
00836     }
00837 
00838     void MultiListBox::setCoord(int _left, int _top, int _width, int _height)
00839     {
00840         setCoord(IntCoord(_left, _top, _width, _height));
00841     }
00842 
00843     bool MultiListBox::getUpdateByResize()
00844     {
00845         if (mWidgetEmpty != nullptr)
00846             return true;
00847 
00848         for (VectorColumnInfo::iterator item = mVectorColumnInfo.begin(); item != mVectorColumnInfo.end(); ++item)
00849         {
00850             if ((*item).sizeType == ResizingPolicy::Fill)
00851                 return true;
00852         }
00853         return false;
00854     }
00855 
00856     int MultiListBox::getColumnWidth(size_t _index, int _freeSpace, size_t _countStars, size_t _lastIndexStar, int _starWidth) const
00857     {
00858         const ColumnInfo& info = mVectorColumnInfo[_index];
00859 
00860         if (info.sizeType == ResizingPolicy::Auto)
00861         {
00862             return info.realWidth;
00863         }
00864         else if (info.sizeType == ResizingPolicy::Fixed)
00865         {
00866             return info.realWidth;
00867         }
00868         else if (info.sizeType == ResizingPolicy::Fill)
00869         {
00870             if (_lastIndexStar == _index)
00871             {
00872                 return _starWidth + _freeSpace - (_starWidth * _countStars);
00873             }
00874             else
00875             {
00876                 return _starWidth;
00877             }
00878         }
00879         return 0;
00880     }
00881 
00882     int MultiListBox::updateWidthColumns(size_t& _countStars, size_t& _lastIndexStar)
00883     {
00884         _countStars = 0;
00885         _lastIndexStar = ITEM_NONE;
00886 
00887         int width = 0;
00888 
00889         for (size_t index = 0; index < mVectorColumnInfo.size(); ++ index)
00890         {
00891             ColumnInfo& info = mVectorColumnInfo[index];
00892 
00893             if (info.sizeType == ResizingPolicy::Auto)
00894             {
00895                 info.realWidth = info.button->getWidth() - info.button->getTextRegion().width + info.button->getTextSize().width;
00896             }
00897             else if (info.sizeType == ResizingPolicy::Fixed)
00898             {
00899                 info.realWidth =  info.width < 0 ? 0 : info.width;
00900             }
00901             else if (info.sizeType == ResizingPolicy::Fill)
00902             {
00903                 info.realWidth = 0;
00904                 _countStars ++;
00905                 _lastIndexStar = index;
00906             }
00907             else
00908             {
00909                 info.realWidth = 0;
00910             }
00911 
00912             width += info.realWidth;
00913         }
00914 
00915         return width;
00916     }
00917 
00918     void MultiListBox::updateColumns()
00919     {
00920         size_t countStars = 0;
00921         size_t lastIndexStar = ITEM_NONE;
00922 
00923         int allColumnsWidth = updateWidthColumns(countStars, lastIndexStar);
00924         int clientWidth = mClient->getWidth();
00925         int separatorsWidth = mVectorColumnInfo.empty() ? 0 : (mVectorColumnInfo.size() - 1) * mWidthSeparator;
00926         int freeSpace = clientWidth - separatorsWidth - allColumnsWidth;
00927         int starWidth = (countStars != 0 && freeSpace > 0) ? (freeSpace / countStars) : 0;
00928 
00929         mWidthBar = 0;
00930         for (size_t index = 0; index < mVectorColumnInfo.size(); ++ index)
00931         {
00932             ColumnInfo& info = mVectorColumnInfo[index];
00933 
00934             int columnWidth = getColumnWidth(index, freeSpace, countStars, lastIndexStar, starWidth);
00935 
00936             if (mHeaderPlace != nullptr)
00937             {
00938                 info.item->setCoord(mWidthBar, 0, columnWidth, mClient->getHeight());
00939             }
00940             else
00941             {
00942                 info.item->setCoord(mWidthBar, mHeightButton, columnWidth, mClient->getHeight() - mHeightButton);
00943             }
00944 
00945             info.button->setCoord(mWidthBar, 0, columnWidth, getButtonHeight());
00946             info.button->_setInternalData(index);
00947 
00948             mWidthBar += columnWidth;
00949 
00950             // промежуток между листами
00951             Widget* separator = getSeparator(index);
00952             if (separator)
00953             {
00954                 separator->setCoord(mWidthBar, 0, mWidthSeparator, mClient->getHeight());
00955             }
00956 
00957             mWidthBar += mWidthSeparator;
00958         }
00959 
00960         redrawButtons();
00961         updateOnlyEmpty();
00962     }
00963 
00964 } // namespace MyGUI