MyGUI
3.0.3
|
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