MyGUI 3.0.1

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