• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

MyGUI_List.cpp

Go to the documentation of this file.
00001 
00007 /*
00008     This file is part of MyGUI.
00009     
00010     MyGUI is free software: you can redistribute it and/or modify
00011     it under the terms of the GNU Lesser General Public License as published by
00012     the Free Software Foundation, either version 3 of the License, or
00013     (at your option) any later version.
00014     
00015     MyGUI is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU Lesser General Public License for more details.
00019     
00020     You should have received a copy of the GNU Lesser General Public License
00021     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00022 */
00023 #include "MyGUI_Precompiled.h"
00024 #include "MyGUI_Common.h"
00025 #include "MyGUI_List.h"
00026 #include "MyGUI_Button.h"
00027 #include "MyGUI_VScroll.h"
00028 #include "MyGUI_ResourceSkin.h"
00029 #include "MyGUI_InputManager.h"
00030 
00031 namespace MyGUI
00032 {
00033 
00034     List::List() :
00035         mWidgetScroll(nullptr),
00036         mTopIndex(0),
00037         mOffsetTop(0),
00038         mRangeIndex(-1),
00039         mLastRedrawLine(0),
00040         mIndexSelect(ITEM_NONE),
00041         mLineActive(ITEM_NONE),
00042         mIsFocus(false),
00043         mNeedVisibleScroll(true)
00044     {
00045     }
00046 
00047     void List::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, WidgetPtr _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
00048     {
00049         Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
00050 
00051         initialiseWidgetSkin(_info);
00052     }
00053 
00054     List::~List()
00055     {
00056         shutdownWidgetSkin();
00057     }
00058 
00059     void List::baseChangeWidgetSkin(ResourceSkin* _info)
00060     {
00061         shutdownWidgetSkin();
00062         Base::baseChangeWidgetSkin(_info);
00063         initialiseWidgetSkin(_info);
00064     }
00065 
00066     void List::initialiseWidgetSkin(ResourceSkin* _info)
00067     {
00068         // нам нужен фокус клавы
00069         mNeedKeyFocus = true;
00070 
00071         for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter) {
00072             if (*(*iter)->_getInternalData<std::string>() == "VScroll") {
00073                 MYGUI_DEBUG_ASSERT( ! mWidgetScroll, "widget already assigned");
00074                 mWidgetScroll = (*iter)->castType<VScroll>();
00075                 mWidgetScroll->eventScrollChangePosition = newDelegate(this, &List::notifyScrollChangePosition);
00076                 mWidgetScroll->eventMouseButtonPressed = newDelegate(this, &List::notifyMousePressed);
00077             }
00078             else if (*(*iter)->_getInternalData<std::string>() == "Client") {
00079                 MYGUI_DEBUG_ASSERT( ! mWidgetClient, "widget already assigned");
00080                 mWidgetClient = (*iter);
00081                 mWidgetClient->eventMouseButtonPressed = newDelegate(this, &List::notifyMousePressed);
00082             }
00083         }
00084         MYGUI_ASSERT(nullptr != mWidgetScroll, "Child VScroll not found in skin (List must have VScroll)");
00085         MYGUI_ASSERT(nullptr != mWidgetClient, "Child Widget Client not found in skin (List must have Client)");
00086 
00087         // парсим свойства
00088         const MapString& properties = _info->getProperties();
00089         MapString::const_iterator iterS = properties.find("SkinLine");
00090         if (iterS != properties.end()) mSkinLine = iterS->second;
00091         MYGUI_ASSERT(false == mSkinLine.empty(), "SkinLine property not found (List must have SkinLine property)");
00092 
00093         iterS = properties.find("HeightLine");
00094         if (iterS != properties.end()) mHeightLine = utility::parseInt(iterS->second);
00095         if (mHeightLine < 1) mHeightLine = 1;
00096 
00097 
00098         mWidgetScroll->setScrollPage((size_t)mHeightLine);
00099         mWidgetScroll->setScrollViewPage((size_t)mHeightLine);
00100 
00101         updateScroll();
00102         updateLine();
00103 
00104     }
00105 
00106     void List::shutdownWidgetSkin()
00107     {
00108         mWidgetScroll = nullptr;
00109         mWidgetClient = nullptr;
00110     }
00111 
00112     void List::onMouseWheel(int _rel)
00113     {
00114         notifyMouseWheel(nullptr, _rel);
00115 
00116         Base::onMouseWheel(_rel);
00117     }
00118 
00119     void List::onKeySetFocus(WidgetPtr _old)
00120     {
00121         mIsFocus = true;
00122         _updateState();
00123 
00124         Base::onKeySetFocus(_old);
00125     }
00126 
00127     void List::onKeyLostFocus(WidgetPtr _new)
00128     {
00129         mIsFocus = false;
00130         _updateState();
00131 
00132         Base::onKeyLostFocus(_new);
00133     }
00134 
00135     void List::onKeyButtonPressed(KeyCode _key, Char _char)
00136     {
00137         if (getItemCount() == 0) {
00138 
00139             Base::onKeyButtonPressed(_key, _char);
00140             return;
00141         }
00142 
00143         // очень секретный метод, запатентованный механизм движения курсора
00144         size_t sel = mIndexSelect;
00145 
00146         if (_key == KeyCode::ArrowUp) {
00147 
00148             if (sel != 0) {
00149                 if (sel == ITEM_NONE) sel = 0;
00150                 else sel --;
00151             }
00152 
00153         }
00154         else if (_key == KeyCode::ArrowDown) {
00155 
00156             if (sel == ITEM_NONE) sel = 0;
00157             else sel ++;
00158 
00159             if (sel >= getItemCount()) {
00160                 // старое значение
00161                 sel = mIndexSelect;
00162             }
00163 
00164         }
00165         else if (_key == KeyCode::Home) {
00166 
00167             if (sel != 0) sel = 0;
00168 
00169         }
00170         else if (_key == KeyCode::End) {
00171 
00172             if (sel != (getItemCount() - 1)) {
00173                 sel = getItemCount() - 1;
00174             }
00175 
00176         }
00177         else if (_key == KeyCode::PageUp) {
00178 
00179             if (sel != 0) {
00180                 if (sel == ITEM_NONE) sel = 0;
00181                 else {
00182                     size_t page = mWidgetClient->getHeight() / mHeightLine;
00183                     if (sel <= page) sel = 0;
00184                     else sel -= page;
00185                 }
00186             }
00187 
00188         }
00189         else if (_key == KeyCode::PageDown) {
00190 
00191             if (sel != (getItemCount() - 1)) {
00192                 if (sel == ITEM_NONE) sel = 0;
00193                 else {
00194                     sel += mWidgetClient->getHeight() / mHeightLine;
00195                     if (sel >= getItemCount()) sel = getItemCount() - 1;
00196                 }
00197             }
00198 
00199         }
00200         else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter)) {
00201             if (sel != ITEM_NONE) {
00202                 //FIXME нас могут удалить
00203                 eventListSelectAccept(this, sel);
00204 
00205                 Base::onKeyButtonPressed(_key, _char);
00206                 // выходим, так как изменили колличество строк
00207                 return;
00208             }
00209 
00210         }
00211 
00212         if (sel != mIndexSelect) {
00213             if ( false == isItemVisibleAt(sel)) {
00214                 beginToItemAt(sel);
00215                 _sendEventChangeScroll(mWidgetScroll->getScrollPosition());
00216             }
00217             setIndexSelected(sel);
00218 
00219             // изменилась позиция
00220             // FIXME нас могут удалить
00221             eventListChangePosition(this, mIndexSelect);
00222         }
00223 
00224         Base::onKeyButtonPressed(_key, _char);
00225     }
00226 
00227     void List::notifyMouseWheel(WidgetPtr _sender, int _rel)
00228     {
00229         if (mRangeIndex <= 0) return;
00230 
00231         int offset = (int)mWidgetScroll->getScrollPosition();
00232         if (_rel < 0) offset += mHeightLine;
00233         else  offset -= mHeightLine;
00234 
00235         if (offset >= mRangeIndex) offset = mRangeIndex;
00236         else if (offset < 0) offset = 0;
00237 
00238         if ((int)mWidgetScroll->getScrollPosition() == offset) return;
00239 
00240         mWidgetScroll->setScrollPosition(offset);
00241         _setScrollView(offset);
00242         _sendEventChangeScroll(offset);
00243     }
00244 
00245     void List::notifyScrollChangePosition(VScrollPtr _sender, size_t _position)
00246     {
00247         _setScrollView(_position);
00248         _sendEventChangeScroll(_position);
00249     }
00250 
00251     void List::notifyMousePressed(WidgetPtr _sender, int _left, int _top, MouseButton _id)
00252     {
00253         if (MouseButton::Left != _id) return;
00254 
00255         if (_sender == mWidgetScroll) return;
00256 
00257         // если выделен клиент, то сбрасываем
00258         if (_sender == mWidgetClient) {
00259 
00260             if (mIndexSelect != ITEM_NONE) {
00261                 _selectIndex(mIndexSelect, false);
00262                 mIndexSelect = ITEM_NONE;
00263                 eventListChangePosition(this, mIndexSelect);
00264             }
00265             eventListMouseItemActivate(this, mIndexSelect);
00266 
00267         // если не клиент, то просчитывам
00268         }
00269         // ячейка может быть скрыта
00270         else if (_sender->isVisible()) {
00271 
00272 #if MYGUI_DEBUG_MODE == 1
00273             _checkMapping("List::notifyMousePressed");
00274             MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>(), mWidgetLines.size(), "List::notifyMousePressed");
00275             MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>() + mTopIndex, mItemsInfo.size(), "List::notifyMousePressed");
00276 #endif
00277 
00278             size_t index = *_sender->_getInternalData<size_t>() + mTopIndex;
00279 
00280             if (mIndexSelect != index) {
00281                 _selectIndex(mIndexSelect, false);
00282                 _selectIndex(index, true);
00283                 mIndexSelect = index;
00284                 eventListChangePosition(this, mIndexSelect);
00285             }
00286             eventListMouseItemActivate(this, mIndexSelect);
00287 
00288         }
00289     }
00290 
00291     void List::notifyMouseDoubleClick(WidgetPtr _sender)
00292     {
00293         if (mIndexSelect != ITEM_NONE)
00294             eventListSelectAccept(this, mIndexSelect);
00295     }
00296 
00297     void List::setPosition(const IntPoint& _point)
00298     {
00299         Base::setPosition(_point);
00300     }
00301 
00302     void List::setSize(const IntSize& _size)
00303     {
00304         Base::setSize(_size);
00305 
00306         updateScroll();
00307         updateLine();
00308     }
00309 
00310     void List::setCoord(const IntCoord& _coord)
00311     {
00312         Base::setCoord(_coord);
00313 
00314         updateScroll();
00315         updateLine();
00316     }
00317 
00318     void List::updateScroll()
00319     {
00320         mRangeIndex = (mHeightLine * (int)mItemsInfo.size()) - mWidgetClient->getHeight();
00321 
00322         if ( (false == mNeedVisibleScroll) || (mRangeIndex < 1) || (mWidgetScroll->getLeft() <= mWidgetClient->getLeft()) )
00323         {
00324             if (mWidgetScroll->isVisible()) {
00325                 mWidgetScroll->setVisible(false);
00326                 // увеличиваем клиентскую зону на ширину скрола
00327                 mWidgetClient->setSize(mWidgetClient->getWidth() + mWidgetScroll->getWidth(), mWidgetClient->getHeight());
00328             }
00329         }
00330         else if (false == mWidgetScroll->isVisible())
00331         {
00332             mWidgetClient->setSize(mWidgetClient->getWidth() - mWidgetScroll->getWidth(), mWidgetClient->getHeight());
00333             mWidgetScroll->setVisible(true);
00334         }
00335 
00336         mWidgetScroll->setScrollRange(mRangeIndex + 1);
00337         if ((int)mItemsInfo.size()) mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * mWidgetClient->getHeight() / mHeightLine / (int)mItemsInfo.size() );
00338     }
00339 
00340     void List::updateLine(bool _reset)
00341     {
00342         // сбрасываем
00343         if (_reset) {
00344             mOldSize.clear();
00345             mLastRedrawLine = 0;
00346         }
00347 
00348         // позиция скролла
00349         int position = mTopIndex * mHeightLine + mOffsetTop;
00350 
00351         // если высота увеличивалась то добавляем виджеты
00352         if (mOldSize.height < mCoord.height) {
00353 
00354             int height = (int)mWidgetLines.size() * mHeightLine - mOffsetTop;
00355 
00356             // до тех пор, пока не достигнем максимального колличества, и всегда на одну больше
00357             while ( (height <= (mWidgetClient->getHeight() + mHeightLine)) && (mWidgetLines.size() < mItemsInfo.size()) ) {
00358                 // создаем линию
00359                 WidgetPtr line = mWidgetClient->createWidgetT("Button", mSkinLine, 0, height, mWidgetClient->getWidth(), mHeightLine, Align::Top | Align::HStretch);
00360                 // подписываемся на всякие там события
00361                 line->eventMouseButtonPressed = newDelegate(this, &List::notifyMousePressed);
00362                 line->eventMouseButtonDoubleClick = newDelegate(this, &List::notifyMouseDoubleClick);
00363                 line->eventMouseWheel = newDelegate(this, &List::notifyMouseWheel);
00364                 line->eventMouseSetFocus = newDelegate(this, &List::notifyMouseSetFocus);
00365                 line->eventMouseLostFocus = newDelegate(this, &List::notifyMouseLostFocus);
00366                 // присваиваем порядковый номер, для простоты просчета
00367                 line->_setInternalData((size_t)mWidgetLines.size());
00368                 // и сохраняем
00369                 mWidgetLines.push_back(line);
00370                 height += mHeightLine;
00371             };
00372 
00373             // проверяем на возможность не менять положение списка
00374             if (position >= mRangeIndex) {
00375 
00376                 // размер всех помещается в клиент
00377                 if (mRangeIndex <= 0) {
00378 
00379                     // обнуляем, если надо
00380                     if (position || mOffsetTop || mTopIndex) {
00381 
00382                         position = 0;
00383                         mTopIndex = 0;
00384                         mOffsetTop = 0;
00385                         mLastRedrawLine = 0; // чтобы все перерисовалось
00386 
00387                         // выравниваем
00388                         int offset = 0;
00389                         for (size_t pos=0; pos<mWidgetLines.size(); pos++) {
00390                             mWidgetLines[pos]->setPosition(0, offset);
00391                             offset += mHeightLine;
00392                         }
00393                     }
00394 
00395                 }
00396                 else {
00397 
00398                     // прижимаем список к нижней границе
00399                     int count = mWidgetClient->getHeight() / mHeightLine;
00400                     mOffsetTop = mHeightLine - (mWidgetClient->getHeight() % mHeightLine);
00401 
00402                     if (mOffsetTop == mHeightLine) {
00403                         mOffsetTop = 0;
00404                         count --;
00405                     }
00406 
00407                     int top = (int)mItemsInfo.size() - count - 1;
00408 
00409                     // выравниваем
00410                     int offset = 0 - mOffsetTop;
00411                     for (size_t pos=0; pos<mWidgetLines.size(); pos++) {
00412                         mWidgetLines[pos]->setPosition(0, offset);
00413                         offset += mHeightLine;
00414                     }
00415 
00416                     // высчитываем положение, должно быть максимальным
00417                     position = top * mHeightLine + mOffsetTop;
00418 
00419                     // если индех изменился, то перерисовываем линии
00420                     if (top != mTopIndex) {
00421                         mTopIndex = top;
00422                         _redrawItemRange();
00423                     }
00424 
00425                 }
00426             }
00427 
00428             // увеличился размер, но прокрутки вниз небыло, обновляем линии снизу
00429             _redrawItemRange(mLastRedrawLine);
00430 
00431         } // if (old_cy < mCoord.height)
00432 
00433         // просчитываем положение скролла
00434         mWidgetScroll->setScrollPosition(position);
00435 
00436         mOldSize.width = mCoord.width;
00437         mOldSize.height = mCoord.height;
00438 
00439 #if MYGUI_DEBUG_MODE == 1
00440         _checkMapping("List::updateLine");
00441 #endif
00442 
00443     }
00444 
00445     void List::_redrawItemRange(size_t _start)
00446     {
00447         // перерисовываем линии, только те, что видны
00448         size_t pos = _start;
00449         for (; pos<mWidgetLines.size(); pos++) {
00450             // индекс в нашем массиве
00451             size_t index = pos + (size_t)mTopIndex;
00452 
00453             // не будем заходить слишком далеко
00454             if (index >= mItemsInfo.size()) {
00455                 // запоминаем последнюю перерисованную линию
00456                 mLastRedrawLine = pos;
00457                 break;
00458             }
00459             if (mWidgetLines[pos]->getTop() > mWidgetClient->getHeight()) {
00460                 // запоминаем последнюю перерисованную линию
00461                 mLastRedrawLine = pos;
00462                 break;
00463             }
00464 
00465             // если был скрыт, то покажем
00466             mWidgetLines[pos]->setVisible(true);
00467             // обновляем текст
00468             mWidgetLines[pos]->setCaption(mItemsInfo[index].first);
00469 
00470             // если нужно выделить ,то выделим
00471             static_cast<ButtonPtr>(mWidgetLines[pos])->setButtonPressed(index == mIndexSelect);
00472         }
00473 
00474         // если цикл весь прошли, то ставим максимальную линию
00475         if (pos >= mWidgetLines.size()) mLastRedrawLine = pos;
00476         else {
00477             //WidgetPtr focus = InputManager::getInstance().getMouseFocusWidget();
00478             for (; pos<mWidgetLines.size(); pos++) {
00479                 static_cast<ButtonPtr>(mWidgetLines[pos])->setButtonPressed(false);
00480                 static_cast<ButtonPtr>(mWidgetLines[pos])->setVisible(false);
00481                 //if (focus == mWidgetLines[pos]) InputManager::getInstance()._unlinkWidget(focus);
00482             }
00483         }
00484 
00485 #if MYGUI_DEBUG_MODE == 1
00486         _checkMapping("List::_redrawItemRange");
00487 #endif
00488 
00489     }
00490 
00491     // перерисовывает индекс
00492     void List::_redrawItem(size_t _index)
00493     {
00494         // невидно
00495         if (_index < (size_t)mTopIndex) return;
00496         _index -= (size_t)mTopIndex;
00497         // тоже невидно
00498         if (_index >= mLastRedrawLine) return;
00499 
00500         MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "List::_redrawItem");
00501         // перерисовываем
00502         mWidgetLines[_index]->setCaption(mItemsInfo[_index + mTopIndex].first);
00503 
00504 #if MYGUI_DEBUG_MODE == 1
00505         _checkMapping("List::_redrawItem");
00506 #endif
00507 
00508     }
00509 
00510     void List::insertItemAt(size_t _index, const UString& _name, Any _data)
00511     {
00512         MYGUI_ASSERT_RANGE_INSERT(_index, mItemsInfo.size(), "List::insertItemAt");
00513         if (_index == ITEM_NONE) _index = mItemsInfo.size();
00514 
00515         // вставляем физически
00516         mItemsInfo.insert(mItemsInfo.begin() + _index, PairItem(_name, _data));
00517 
00518         // если надо, то меняем выделенный элемент
00519         if ( (mIndexSelect != ITEM_NONE) && (_index <= mIndexSelect) ) mIndexSelect++;
00520 
00521         // строка, до первого видимого элемента
00522         if ( (_index <= (size_t)mTopIndex) && (mRangeIndex > 0) ) {
00523             mTopIndex ++;
00524             // просчитываем положение скролла
00525             mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() + mHeightLine);
00526             if ((int)mItemsInfo.size()) mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * mWidgetClient->getHeight() / mHeightLine / (int)mItemsInfo.size() );
00527             mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
00528             mRangeIndex += mHeightLine;
00529 
00530         }
00531         else {
00532 
00533             // высчитывам положение строки
00534             int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
00535 
00536             // строка, после последнего видимого элемента, плюс одна строка (потому что для прокрутки нужно на одну строчку больше)
00537             if (mWidgetClient->getHeight() < (offset - mHeightLine)) {
00538                 // просчитываем положение скролла
00539                 mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() + mHeightLine);
00540                 if ((int)mItemsInfo.size()) mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * mWidgetClient->getHeight() / mHeightLine / (int)mItemsInfo.size() );
00541                 mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
00542                 mRangeIndex += mHeightLine;
00543 
00544             // строка в видимой области
00545             } else {
00546 
00547                 // обновляем все
00548                 updateScroll();
00549                 updateLine(true);
00550 
00551                 // позже сюда еще оптимизацию по колличеству перерисовок
00552             }
00553         }
00554 
00555 #if MYGUI_DEBUG_MODE == 1
00556         _checkMapping("List::insertItemAt");
00557 #endif
00558 
00559     }
00560 
00561     void List::removeItemAt(size_t _index)
00562     {
00563         MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "List::removeItemAt");
00564 
00565         // удяляем физически строку
00566         mItemsInfo.erase(mItemsInfo.begin() + _index);
00567 
00568         // если надо, то меняем выделенный элемент
00569         if (mItemsInfo.empty()) mIndexSelect = ITEM_NONE;
00570         else if (mIndexSelect != ITEM_NONE) {
00571             if (_index < mIndexSelect) mIndexSelect--;
00572             else if ( (_index == mIndexSelect) && (mIndexSelect == (mItemsInfo.size())) ) mIndexSelect--;
00573         }
00574 
00575         // если виджетов стало больше , то скрываем крайний
00576         if (mWidgetLines.size() > mItemsInfo.size()) {
00577             mWidgetLines[mItemsInfo.size()]->setVisible(false);
00578         }
00579 
00580         // строка, до первого видимого элемента
00581         if (_index < (size_t)mTopIndex) {
00582             mTopIndex --;
00583             // просчитываем положение скролла
00584             mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() - mHeightLine);
00585             if ((int)mItemsInfo.size()) mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * mWidgetClient->getHeight() / mHeightLine / (int)mItemsInfo.size() );
00586             mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
00587             mRangeIndex -= mHeightLine;
00588 
00589         }
00590         else {
00591 
00592             // высчитывам положение удаляемой строки
00593             int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
00594 
00595             // строка, после последнего видимого элемента
00596             if (mWidgetClient->getHeight() < offset) {
00597                 // просчитываем положение скролла
00598                 mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() - mHeightLine);
00599                 if ((int)mItemsInfo.size()) mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * mWidgetClient->getHeight() / mHeightLine / (int)mItemsInfo.size() );
00600                 mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
00601                 mRangeIndex -= mHeightLine;
00602 
00603             // строка в видимой области
00604             }
00605             else {
00606 
00607                 // обновляем все
00608                 updateScroll();
00609                 updateLine(true);
00610 
00611                 // позже сюда еще оптимизацию по колличеству перерисовок
00612             }
00613         }
00614 
00615 #if MYGUI_DEBUG_MODE == 1
00616         _checkMapping("List::removeItemAt");
00617 #endif
00618 
00619     }
00620 
00621     void List::setIndexSelected(size_t _index)
00622     {
00623         MYGUI_ASSERT_RANGE_AND_NONE(_index, mItemsInfo.size(), "List::setIndexSelected");
00624         if (mIndexSelect != _index) {
00625             _selectIndex(mIndexSelect, false);
00626             _selectIndex(_index, true);
00627             mIndexSelect = _index;
00628         }
00629     }
00630 
00631     void List::_selectIndex(size_t _index, bool _select)
00632     {
00633         if (_index == ITEM_NONE) return;
00634         // не видно строки
00635         if (_index < (size_t)mTopIndex) return;
00636         // высчитывам положение строки
00637         int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
00638         // строка, после последнего видимого элемента
00639         if (mWidgetClient->getHeight() < offset) return;
00640 
00641         static_cast<ButtonPtr>(mWidgetLines[_index-mTopIndex])->setButtonPressed(_select);
00642 
00643 #if MYGUI_DEBUG_MODE == 1
00644         _checkMapping("List::_selectIndex");
00645 #endif
00646 
00647     }
00648 
00649     void List::beginToItemAt(size_t _index)
00650     {
00651         MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "List::beginToItemAt");
00652         if (mRangeIndex <= 0) return;
00653 
00654         int offset = (int)_index * mHeightLine;
00655         if (offset >= mRangeIndex) offset = mRangeIndex;
00656 
00657         if ((int)mWidgetScroll->getScrollPosition() == offset) return;
00658 
00659         mWidgetScroll->setScrollPosition(offset);
00660         notifyScrollChangePosition(nullptr, offset);
00661 
00662 #if MYGUI_DEBUG_MODE == 1
00663         _checkMapping("List::beginToItemAt");
00664 #endif
00665 
00666     }
00667 
00668     // видим ли мы элемент, полностью или нет
00669     bool List::isItemVisibleAt(size_t _index, bool _fill)
00670     {
00671         // если элемента нет, то мы его не видим (в том числе когда их вообще нет)
00672         if (_index >= mItemsInfo.size()) return false;
00673         // если скрола нет, то мы палюбак видим
00674         if (mRangeIndex <= 0) return true;
00675 
00676         // строка, до первого видимого элемента
00677         if (_index < (size_t)mTopIndex) return false;
00678 
00679         // строка это верхний выделенный
00680         if (_index == (size_t)mTopIndex) {
00681             if ( (mOffsetTop != 0) && (_fill) ) return false; // нам нужна полностью видимость
00682             return true;
00683         }
00684 
00685         // высчитывам положение строки
00686         int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
00687 
00688         // строка, после последнего видимого элемента
00689         if (mWidgetClient->getHeight() < offset) return false;
00690 
00691         // если мы внизу и нам нужен целый
00692         if ((mWidgetClient->getHeight() < (offset + mHeightLine)) && (_fill) ) return false;
00693 
00694         return true;
00695     }
00696 
00697     void List::removeAllItems()
00698     {
00699         mTopIndex = 0;
00700         mIndexSelect = ITEM_NONE;
00701         mOffsetTop = 0;
00702 
00703         mItemsInfo.clear();
00704 
00705         int offset = 0;
00706         for (size_t pos=0; pos<mWidgetLines.size(); pos++)
00707         {
00708             mWidgetLines[pos]->setVisible(false);
00709             mWidgetLines[pos]->setPosition(0, offset);
00710             offset += mHeightLine;
00711         }
00712 
00713         // обновляем все
00714         updateScroll();
00715         updateLine(true);
00716 
00717 #if MYGUI_DEBUG_MODE == 1
00718         _checkMapping("List::removeAllItems");
00719 #endif
00720 
00721     }
00722 
00723     void List::setItemNameAt(size_t _index, const UString& _name)
00724     {
00725         MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "List::setItemNameAt");
00726         mItemsInfo[_index].first =_name;
00727         _redrawItem(_index);
00728     }
00729 
00730     void List::setItemDataAt(size_t _index, Any _data)
00731     {
00732         MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "List::setItemDataAt");
00733         mItemsInfo[_index].second = _data;
00734         _redrawItem(_index);
00735     }
00736 
00737     const UString& List::getItemNameAt(size_t _index)
00738     {
00739         MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "List::getItemNameAt");
00740         return mItemsInfo[_index].first;
00741     }
00742 
00743     void List::notifyMouseSetFocus(WidgetPtr _sender, WidgetPtr _old)
00744     {
00745 
00746 #if MYGUI_DEBUG_MODE == 1
00747         MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>(), mWidgetLines.size(), "List::notifyMouseSetFocus");
00748 #endif
00749 
00750         mLineActive = *_sender->_getInternalData<size_t>();
00751         eventListMouseItemFocus(this, mLineActive);
00752     }
00753 
00754     void List::notifyMouseLostFocus(WidgetPtr _sender, WidgetPtr _new)
00755     {
00756         if ((nullptr == _new) || (_new->getParent() != mWidgetClient)) {
00757             mLineActive = ITEM_NONE;
00758             eventListMouseItemFocus(this, ITEM_NONE);
00759         }
00760     }
00761 
00762     void List::_setItemFocus(size_t _index, bool _focus)
00763     {
00764         MYGUI_ASSERT_RANGE(_index, mWidgetLines.size(), "List::_setItemFocus");
00765         static_cast<ButtonPtr>(mWidgetLines[_index])->_setMouseFocus(_focus);
00766     }
00767 
00768     void List::setScrollVisible(bool _visible)
00769     {
00770         if (mNeedVisibleScroll == _visible) return;
00771         mNeedVisibleScroll = _visible;
00772         updateScroll();
00773     }
00774 
00775     void List::setScrollPosition(size_t _position)
00776     {
00777         if (mWidgetScroll->getScrollRange() > _position) {
00778             mWidgetScroll->setScrollPosition(_position);
00779             _setScrollView(_position);
00780         }
00781     }
00782 
00783     void List::_setScrollView(size_t _position)
00784     {
00785         mOffsetTop = ((int)_position % mHeightLine);
00786 
00787         // смещение с отрицательной стороны
00788         int offset = 0 - mOffsetTop;
00789 
00790         for (size_t pos=0; pos<mWidgetLines.size(); pos++) {
00791             mWidgetLines[pos]->setPosition(IntPoint(0, offset));
00792             offset += mHeightLine;
00793         }
00794 
00795         // если индех изменился, то перерисовываем линии
00796         int top = ((int)_position / mHeightLine);
00797         if (top != mTopIndex) {
00798             mTopIndex = top;
00799             _redrawItemRange();
00800         }
00801 
00802         // прорисовываем все нижние строки, если они появились
00803         _redrawItemRange(mLastRedrawLine);
00804     }
00805 
00806     void List::_sendEventChangeScroll(size_t _position)
00807     {
00808         eventListChangeScroll(this, _position);
00809         if (ITEM_NONE != mLineActive) eventListMouseItemFocus(this, mLineActive);
00810     }
00811 
00812     void List::swapItemsAt(size_t _index1, size_t _index2)
00813     {
00814         MYGUI_ASSERT_RANGE(_index1, mItemsInfo.size(), "List::swapItemsAt");
00815         MYGUI_ASSERT_RANGE(_index2, mItemsInfo.size(), "List::swapItemsAt");
00816 
00817         if (_index1 == _index2) return;
00818 
00819         std::swap(mItemsInfo[_index1], mItemsInfo[_index2]);
00820 
00821         _redrawItem(_index1);
00822         _redrawItem(_index2);
00823     }
00824 
00825     void List::_checkMapping(const std::string& _owner)
00826     {
00827         size_t count_pressed = 0;
00828         size_t count_show = 0;
00829 
00830         for (size_t pos=0; pos<mWidgetLines.size(); pos++) {
00831             MYGUI_ASSERT(pos == *mWidgetLines[pos]->_getInternalData<size_t>(), _owner);
00832             static_cast<ButtonPtr>(mWidgetLines[pos])->getButtonPressed() ? count_pressed ++ : 0;
00833             static_cast<ButtonPtr>(mWidgetLines[pos])->isVisible() ? count_show ++ : 0;
00834         }
00835         MYGUI_ASSERT(count_pressed < 2, _owner);
00836         //MYGUI_ASSERT((count_show + mOffsetTop) <= mItemsInfo.size(), _owner);
00837     }
00838 
00839     void List::_checkAlign()
00840     {
00841         // максимальная высота всех строк
00842         int max_height = mItemsInfo.size() * mHeightLine;
00843         // видимая высота
00844         int visible_height = mWidgetClient->getHeight();
00845 
00846         // все строки помещаются
00847         if (visible_height >= max_height)
00848         {
00849             MYGUI_ASSERT(mTopIndex == 0, "mTopIndex == 0");
00850             MYGUI_ASSERT(mOffsetTop == 0, "mOffsetTop == 0");
00851             int height = 0;
00852             for (size_t pos=0; pos<mWidgetLines.size(); pos++) {
00853                 if (pos >= mItemsInfo.size()) break;
00854                 MYGUI_ASSERT(mWidgetLines[pos]->getTop() == height, "mWidgetLines[pos]->getTop() == height");
00855                 height += mWidgetLines[pos]->getHeight();
00856             }
00857         }
00858     }
00859 
00860     size_t List::findItemIndexWith(const UString& _name)
00861     {
00862         for (size_t pos=0; pos<mItemsInfo.size(); pos++)
00863         {
00864             if (mItemsInfo[pos].first == _name) return pos;
00865         }
00866         return ITEM_NONE;
00867     }
00868 
00869     size_t List::getOptimalHeight()
00870     {
00871         return (mCoord.height - mWidgetClient->getHeight()) + (mItemsInfo.size() * mHeightLine);
00872     }
00873 
00874     void List::setProperty(const std::string& _key, const std::string& _value)
00875     {
00876         if (_key == "List_AddItem") addItem(_value);
00877         else Base::setProperty(_key, _value);
00878     }
00879 
00880 } // namespace MyGUI

Generated on Sun Jan 30 2011 for MyGUI by  doxygen 1.7.1