MyGUI
3.2.0
|
00001 00006 /* 00007 This file is part of MyGUI. 00008 00009 MyGUI is free software: you can redistribute it and/or modify 00010 it under the terms of the GNU Lesser General Public License as published by 00011 the Free Software Foundation, either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 MyGUI is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License 00020 along with MyGUI. If not, see <http://www.gnu.org/licenses/>. 00021 */ 00022 #include "MyGUI_Precompiled.h" 00023 #include "MyGUI_ListBox.h" 00024 #include "MyGUI_Button.h" 00025 #include "MyGUI_ScrollBar.h" 00026 #include "MyGUI_ResourceSkin.h" 00027 #include "MyGUI_InputManager.h" 00028 #include "MyGUI_WidgetManager.h" 00029 00030 namespace MyGUI 00031 { 00032 00033 ListBox::ListBox() : 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 mNeedVisibleScroll(true), 00043 mClient(nullptr) 00044 { 00045 } 00046 00047 void ListBox::initialiseOverride() 00048 { 00049 Base::initialiseOverride(); 00050 00051 // FIXME нам нужен фокус клавы 00052 setNeedKeyFocus(true); 00053 00054 // парсим свойства 00055 if (isUserString("SkinLine")) 00056 mSkinLine = getUserString("SkinLine"); 00057 00058 if (isUserString("HeightLine")) 00059 mHeightLine = utility::parseInt(getUserString("HeightLine")); 00060 00061 if (mHeightLine < 1) 00062 mHeightLine = 1; 00063 00064 assignWidget(mClient, "Client"); 00065 if (mClient != nullptr) 00066 { 00067 mClient->eventMouseButtonPressed += newDelegate(this, &ListBox::notifyMousePressed); 00068 setWidgetClient(mClient); 00069 } 00070 00071 assignWidget(mWidgetScroll, "VScroll"); 00072 if (mWidgetScroll != nullptr) 00073 { 00074 mWidgetScroll->eventScrollChangePosition += newDelegate(this, &ListBox::notifyScrollChangePosition); 00075 mWidgetScroll->eventMouseButtonPressed += newDelegate(this, &ListBox::notifyMousePressed); 00076 mWidgetScroll->setScrollPage((size_t)mHeightLine); 00077 mWidgetScroll->setScrollViewPage((size_t)mHeightLine); 00078 } 00079 00080 updateScroll(); 00081 updateLine(); 00082 } 00083 00084 void ListBox::shutdownOverride() 00085 { 00086 mWidgetScroll = nullptr; 00087 mClient = nullptr; 00088 00089 Base::shutdownOverride(); 00090 } 00091 00092 void ListBox::onMouseWheel(int _rel) 00093 { 00094 notifyMouseWheel(nullptr, _rel); 00095 00096 Base::onMouseWheel(_rel); 00097 } 00098 00099 void ListBox::onKeyButtonPressed(KeyCode _key, Char _char) 00100 { 00101 if (getItemCount() == 0) 00102 { 00103 Base::onKeyButtonPressed(_key, _char); 00104 return; 00105 } 00106 00107 // очень секретный метод, запатентованный механизм движения курсора 00108 size_t sel = mIndexSelect; 00109 00110 if (_key == KeyCode::ArrowUp) 00111 { 00112 if (sel != 0) 00113 { 00114 if (sel == ITEM_NONE) 00115 sel = 0; 00116 else 00117 sel --; 00118 } 00119 } 00120 else if (_key == KeyCode::ArrowDown) 00121 { 00122 if (sel == ITEM_NONE) 00123 sel = 0; 00124 else 00125 sel ++; 00126 00127 if (sel >= getItemCount()) 00128 { 00129 // старое значение 00130 sel = mIndexSelect; 00131 } 00132 } 00133 else if (_key == KeyCode::Home) 00134 { 00135 if (sel != 0) 00136 sel = 0; 00137 } 00138 else if (_key == KeyCode::End) 00139 { 00140 if (sel != (getItemCount() - 1)) 00141 { 00142 sel = getItemCount() - 1; 00143 } 00144 } 00145 else if (_key == KeyCode::PageUp) 00146 { 00147 if (sel != 0) 00148 { 00149 if (sel == ITEM_NONE) 00150 { 00151 sel = 0; 00152 } 00153 else 00154 { 00155 size_t page = _getClientWidget()->getHeight() / mHeightLine; 00156 if (sel <= page) 00157 sel = 0; 00158 else 00159 sel -= page; 00160 } 00161 } 00162 } 00163 else if (_key == KeyCode::PageDown) 00164 { 00165 if (sel != (getItemCount() - 1)) 00166 { 00167 if (sel == ITEM_NONE) 00168 { 00169 sel = 0; 00170 } 00171 else 00172 { 00173 sel += _getClientWidget()->getHeight() / mHeightLine; 00174 if (sel >= getItemCount()) 00175 sel = getItemCount() - 1; 00176 } 00177 } 00178 } 00179 else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter)) 00180 { 00181 if (sel != ITEM_NONE) 00182 { 00183 //FIXME нас могут удалить 00184 eventListSelectAccept(this, sel); 00185 00186 Base::onKeyButtonPressed(_key, _char); 00187 // выходим, так как изменили колличество строк 00188 return; 00189 } 00190 } 00191 00192 if (sel != mIndexSelect) 00193 { 00194 _resetContainer(true); 00195 00196 if (!isItemVisibleAt(sel)) 00197 { 00198 beginToItemAt(sel); 00199 if (mWidgetScroll != nullptr) 00200 _sendEventChangeScroll(mWidgetScroll->getScrollPosition()); 00201 } 00202 setIndexSelected(sel); 00203 00204 // изменилась позиция 00205 // FIXME нас могут удалить 00206 eventListChangePosition(this, mIndexSelect); 00207 } 00208 00209 Base::onKeyButtonPressed(_key, _char); 00210 } 00211 00212 void ListBox::notifyMouseWheel(Widget* _sender, int _rel) 00213 { 00214 if (mRangeIndex <= 0) 00215 return; 00216 00217 if (mWidgetScroll == nullptr) 00218 return; 00219 00220 int offset = (int)mWidgetScroll->getScrollPosition(); 00221 if (_rel < 0) 00222 offset += mHeightLine; 00223 else 00224 offset -= mHeightLine; 00225 00226 if (offset >= mRangeIndex) 00227 offset = mRangeIndex; 00228 else if (offset < 0) 00229 offset = 0; 00230 00231 if ((int)mWidgetScroll->getScrollPosition() == offset) 00232 return; 00233 00234 mWidgetScroll->setScrollPosition(offset); 00235 _setScrollView(offset); 00236 _sendEventChangeScroll(offset); 00237 00238 _resetContainer(true); 00239 } 00240 00241 void ListBox::notifyScrollChangePosition(ScrollBar* _sender, size_t _position) 00242 { 00243 _setScrollView(_position); 00244 _sendEventChangeScroll(_position); 00245 } 00246 00247 void ListBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id) 00248 { 00249 if (MouseButton::Left != _id) 00250 return; 00251 00252 if (_sender == mWidgetScroll) 00253 return; 00254 00255 // если выделен клиент, то сбрасываем 00256 if (_sender == _getClientWidget()) 00257 { 00258 if (mIndexSelect != ITEM_NONE) 00259 { 00260 _selectIndex(mIndexSelect, false); 00261 mIndexSelect = ITEM_NONE; 00262 eventListChangePosition(this, mIndexSelect); 00263 } 00264 eventListMouseItemActivate(this, mIndexSelect); 00265 00266 // если не клиент, то просчитывам 00267 } 00268 // ячейка может быть скрыта 00269 else if (_sender->getVisible()) 00270 { 00271 00272 #if MYGUI_DEBUG_MODE == 1 00273 _checkMapping("ListBox::notifyMousePressed"); 00274 MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>(), mWidgetLines.size(), "ListBox::notifyMousePressed"); 00275 MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>() + mTopIndex, mItemsInfo.size(), "ListBox::notifyMousePressed"); 00276 #endif 00277 00278 size_t index = *_sender->_getInternalData<size_t>() + mTopIndex; 00279 00280 if (mIndexSelect != index) 00281 { 00282 _selectIndex(mIndexSelect, false); 00283 _selectIndex(index, true); 00284 mIndexSelect = index; 00285 eventListChangePosition(this, mIndexSelect); 00286 } 00287 eventListMouseItemActivate(this, mIndexSelect); 00288 } 00289 00290 _resetContainer(true); 00291 } 00292 00293 void ListBox::notifyMouseDoubleClick(Widget* _sender) 00294 { 00295 if (mIndexSelect != ITEM_NONE) 00296 eventListSelectAccept(this, mIndexSelect); 00297 } 00298 00299 void ListBox::setPosition(const IntPoint& _point) 00300 { 00301 Base::setPosition(_point); 00302 } 00303 00304 void ListBox::setSize(const IntSize& _size) 00305 { 00306 Base::setSize(_size); 00307 00308 updateScroll(); 00309 updateLine(); 00310 } 00311 00312 void ListBox::setCoord(const IntCoord& _coord) 00313 { 00314 Base::setCoord(_coord); 00315 00316 updateScroll(); 00317 updateLine(); 00318 } 00319 00320 void ListBox::updateScroll() 00321 { 00322 mRangeIndex = (mHeightLine * (int)mItemsInfo.size()) - _getClientWidget()->getHeight(); 00323 00324 if (mWidgetScroll == nullptr) 00325 return; 00326 00327 if ((!mNeedVisibleScroll) || (mRangeIndex < 1) || (mWidgetScroll->getLeft() <= _getClientWidget()->getLeft())) 00328 { 00329 if (mWidgetScroll->getVisible()) 00330 { 00331 mWidgetScroll->setVisible(false); 00332 // увеличиваем клиентскую зону на ширину скрола 00333 if (mClient != nullptr) 00334 mClient->setSize(mClient->getWidth() + mWidgetScroll->getWidth(), mClient->getHeight()); 00335 } 00336 } 00337 else if (!mWidgetScroll->getVisible()) 00338 { 00339 if (mClient != nullptr) 00340 mClient->setSize(mClient->getWidth() - mWidgetScroll->getWidth(), mClient->getHeight()); 00341 mWidgetScroll->setVisible(true); 00342 } 00343 00344 mWidgetScroll->setScrollRange(mRangeIndex + 1); 00345 if (!mItemsInfo.empty()) 00346 mWidgetScroll->setTrackSize(mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size()); 00347 } 00348 00349 void ListBox::updateLine(bool _reset) 00350 { 00351 // сбрасываем 00352 if (_reset) 00353 { 00354 mOldSize.clear(); 00355 mLastRedrawLine = 0; 00356 _resetContainer(false); 00357 } 00358 00359 // позиция скролла 00360 int position = mTopIndex * mHeightLine + mOffsetTop; 00361 00362 // если высота увеличивалась то добавляем виджеты 00363 if (mOldSize.height < mCoord.height) 00364 { 00365 int height = (int)mWidgetLines.size() * mHeightLine - mOffsetTop; 00366 00367 // до тех пор, пока не достигнем максимального колличества, и всегда на одну больше 00368 while ( (height <= (_getClientWidget()->getHeight() + mHeightLine)) && (mWidgetLines.size() < mItemsInfo.size()) ) 00369 { 00370 // создаем линию 00371 Widget* widget = _getClientWidget()->createWidgetT("Button", mSkinLine, 0, height, _getClientWidget()->getWidth(), mHeightLine, Align::Top | Align::HStretch); 00372 Button* line = widget->castType<Button>(); 00373 // подписываемся на всякие там события 00374 line->eventMouseButtonPressed += newDelegate(this, &ListBox::notifyMousePressed); 00375 line->eventMouseButtonDoubleClick += newDelegate(this, &ListBox::notifyMouseDoubleClick); 00376 line->eventMouseWheel += newDelegate(this, &ListBox::notifyMouseWheel); 00377 line->eventMouseSetFocus += newDelegate(this, &ListBox::notifyMouseSetFocus); 00378 line->eventMouseLostFocus += newDelegate(this, &ListBox::notifyMouseLostFocus); 00379 line->_setContainer(this); 00380 // присваиваем порядковый номер, для простоты просчета 00381 line->_setInternalData((size_t)mWidgetLines.size()); 00382 // и сохраняем 00383 mWidgetLines.push_back(line); 00384 height += mHeightLine; 00385 } 00386 00387 // проверяем на возможность не менять положение списка 00388 if (position >= mRangeIndex) 00389 { 00390 // размер всех помещается в клиент 00391 if (mRangeIndex <= 0) 00392 { 00393 // обнуляем, если надо 00394 if (position || mOffsetTop || mTopIndex) 00395 { 00396 position = 0; 00397 mTopIndex = 0; 00398 mOffsetTop = 0; 00399 mLastRedrawLine = 0; // чтобы все перерисовалось 00400 00401 // выравниваем 00402 int offset = 0; 00403 for (size_t pos = 0; pos < mWidgetLines.size(); pos++) 00404 { 00405 mWidgetLines[pos]->setPosition(0, offset); 00406 offset += mHeightLine; 00407 } 00408 } 00409 } 00410 else 00411 { 00412 // прижимаем список к нижней границе 00413 int count = _getClientWidget()->getHeight() / mHeightLine; 00414 mOffsetTop = mHeightLine - (_getClientWidget()->getHeight() % mHeightLine); 00415 00416 if (mOffsetTop == mHeightLine) 00417 { 00418 mOffsetTop = 0; 00419 count --; 00420 } 00421 00422 int top = (int)mItemsInfo.size() - count - 1; 00423 00424 // выравниваем 00425 int offset = 0 - mOffsetTop; 00426 for (size_t pos = 0; pos < mWidgetLines.size(); pos++) 00427 { 00428 mWidgetLines[pos]->setPosition(0, offset); 00429 offset += mHeightLine; 00430 } 00431 00432 // высчитываем положение, должно быть максимальным 00433 position = top * mHeightLine + mOffsetTop; 00434 00435 // если индех изменился, то перерисовываем линии 00436 if (top != mTopIndex) 00437 { 00438 mTopIndex = top; 00439 _redrawItemRange(); 00440 } 00441 } 00442 } 00443 00444 // увеличился размер, но прокрутки вниз небыло, обновляем линии снизу 00445 _redrawItemRange(mLastRedrawLine); 00446 00447 } // if (old_cy < mCoord.height) 00448 00449 // просчитываем положение скролла 00450 if (mWidgetScroll != nullptr) 00451 mWidgetScroll->setScrollPosition(position); 00452 00453 mOldSize.width = mCoord.width; 00454 mOldSize.height = mCoord.height; 00455 00456 #if MYGUI_DEBUG_MODE == 1 00457 _checkMapping("ListBox::updateLine"); 00458 #endif 00459 } 00460 00461 void ListBox::_redrawItemRange(size_t _start) 00462 { 00463 // перерисовываем линии, только те, что видны 00464 size_t pos = _start; 00465 for (; pos < mWidgetLines.size(); pos++) 00466 { 00467 // индекс в нашем массиве 00468 size_t index = pos + (size_t)mTopIndex; 00469 00470 // не будем заходить слишком далеко 00471 if (index >= mItemsInfo.size()) 00472 { 00473 // запоминаем последнюю перерисованную линию 00474 mLastRedrawLine = pos; 00475 break; 00476 } 00477 if (mWidgetLines[pos]->getTop() > _getClientWidget()->getHeight()) 00478 { 00479 // запоминаем последнюю перерисованную линию 00480 mLastRedrawLine = pos; 00481 break; 00482 } 00483 00484 // если был скрыт, то покажем 00485 mWidgetLines[pos]->setVisible(true); 00486 // обновляем текст 00487 mWidgetLines[pos]->setCaption(mItemsInfo[index].first); 00488 00489 // если нужно выделить ,то выделим 00490 static_cast<Button*>(mWidgetLines[pos])->setStateSelected(index == mIndexSelect); 00491 } 00492 00493 // если цикл весь прошли, то ставим максимальную линию 00494 if (pos >= mWidgetLines.size()) 00495 { 00496 mLastRedrawLine = pos; 00497 } 00498 else 00499 { 00500 //Widget* focus = InputManager::getInstance().getMouseFocusWidget(); 00501 for (; pos < mWidgetLines.size(); pos++) 00502 { 00503 static_cast<Button*>(mWidgetLines[pos])->setStateSelected(false); 00504 static_cast<Button*>(mWidgetLines[pos])->setVisible(false); 00505 //if (focus == mWidgetLines[pos]) InputManager::getInstance()._unlinkWidget(focus); 00506 } 00507 } 00508 00509 #if MYGUI_DEBUG_MODE == 1 00510 _checkMapping("ListBox::_redrawItemRange"); 00511 #endif 00512 } 00513 00514 // перерисовывает индекс 00515 void ListBox::_redrawItem(size_t _index) 00516 { 00517 // невидно 00518 if (_index < (size_t)mTopIndex) 00519 return; 00520 _index -= (size_t)mTopIndex; 00521 // тоже невидно 00522 if (_index >= mLastRedrawLine) 00523 return; 00524 00525 MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::_redrawItem"); 00526 // перерисовываем 00527 mWidgetLines[_index]->setCaption(mItemsInfo[_index + mTopIndex].first); 00528 00529 #if MYGUI_DEBUG_MODE == 1 00530 _checkMapping("ListBox::_redrawItem"); 00531 #endif 00532 } 00533 00534 void ListBox::insertItemAt(size_t _index, const UString& _name, Any _data) 00535 { 00536 MYGUI_ASSERT_RANGE_INSERT(_index, mItemsInfo.size(), "ListBox::insertItemAt"); 00537 if (_index == ITEM_NONE) 00538 _index = mItemsInfo.size(); 00539 00540 // вставляем физически 00541 mItemsInfo.insert(mItemsInfo.begin() + _index, PairItem(_name, _data)); 00542 00543 // если надо, то меняем выделенный элемент 00544 if ((mIndexSelect != ITEM_NONE) && (_index <= mIndexSelect)) 00545 mIndexSelect++; 00546 00547 // строка, до первого видимого элемента 00548 if ((_index <= (size_t)mTopIndex) && (mRangeIndex > 0)) 00549 { 00550 mTopIndex ++; 00551 // просчитываем положение скролла 00552 if (mWidgetScroll != nullptr) 00553 { 00554 mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() + mHeightLine); 00555 if (!mItemsInfo.empty()) 00556 mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() ); 00557 mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop); 00558 } 00559 mRangeIndex += mHeightLine; 00560 } 00561 else 00562 { 00563 // высчитывам положение строки 00564 int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop; 00565 00566 // строка, после последнего видимого элемента, плюс одна строка (потому что для прокрутки нужно на одну строчку больше) 00567 if (_getClientWidget()->getHeight() < (offset - mHeightLine)) 00568 { 00569 // просчитываем положение скролла 00570 if (mWidgetScroll != nullptr) 00571 { 00572 mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() + mHeightLine); 00573 if (!mItemsInfo.empty()) 00574 mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() ); 00575 mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop); 00576 } 00577 mRangeIndex += mHeightLine; 00578 00579 // строка в видимой области 00580 } 00581 else 00582 { 00583 // обновляем все 00584 updateScroll(); 00585 updateLine(true); 00586 00587 // позже сюда еще оптимизацию по колличеству перерисовок 00588 } 00589 } 00590 00591 #if MYGUI_DEBUG_MODE == 1 00592 _checkMapping("ListBox::insertItemAt"); 00593 #endif 00594 } 00595 00596 void ListBox::removeItemAt(size_t _index) 00597 { 00598 MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::removeItemAt"); 00599 00600 // удяляем физически строку 00601 mItemsInfo.erase(mItemsInfo.begin() + _index); 00602 00603 // если надо, то меняем выделенный элемент 00604 if (mItemsInfo.empty()) mIndexSelect = ITEM_NONE; 00605 else if (mIndexSelect != ITEM_NONE) 00606 { 00607 if (_index < mIndexSelect) 00608 mIndexSelect--; 00609 else if ((_index == mIndexSelect) && (mIndexSelect == (mItemsInfo.size()))) 00610 mIndexSelect--; 00611 } 00612 00613 // если виджетов стало больше , то скрываем крайний 00614 if (mWidgetLines.size() > mItemsInfo.size()) 00615 { 00616 mWidgetLines[mItemsInfo.size()]->setVisible(false); 00617 } 00618 00619 // строка, до первого видимого элемента 00620 if (_index < (size_t)mTopIndex) 00621 { 00622 mTopIndex --; 00623 // просчитываем положение скролла 00624 if (mWidgetScroll != nullptr) 00625 { 00626 mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() - mHeightLine); 00627 if (!mItemsInfo.empty()) 00628 mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() ); 00629 mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop); 00630 } 00631 mRangeIndex -= mHeightLine; 00632 } 00633 else 00634 { 00635 // высчитывам положение удаляемой строки 00636 int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop; 00637 00638 // строка, после последнего видимого элемента 00639 if (_getClientWidget()->getHeight() < offset) 00640 { 00641 // просчитываем положение скролла 00642 if (mWidgetScroll != nullptr) 00643 { 00644 mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() - mHeightLine); 00645 if (!mItemsInfo.empty()) 00646 mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() ); 00647 mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop); 00648 } 00649 mRangeIndex -= mHeightLine; 00650 00651 // строка в видимой области 00652 } 00653 else 00654 { 00655 // обновляем все 00656 updateScroll(); 00657 updateLine(true); 00658 00659 // позже сюда еще оптимизацию по колличеству перерисовок 00660 } 00661 } 00662 00663 #if MYGUI_DEBUG_MODE == 1 00664 _checkMapping("ListBox::removeItemAt"); 00665 #endif 00666 } 00667 00668 void ListBox::setIndexSelected(size_t _index) 00669 { 00670 MYGUI_ASSERT_RANGE_AND_NONE(_index, mItemsInfo.size(), "ListBox::setIndexSelected"); 00671 if (mIndexSelect != _index) 00672 { 00673 _selectIndex(mIndexSelect, false); 00674 _selectIndex(_index, true); 00675 mIndexSelect = _index; 00676 } 00677 } 00678 00679 void ListBox::_selectIndex(size_t _index, bool _select) 00680 { 00681 if (_index == ITEM_NONE) 00682 return; 00683 // не видно строки 00684 if (_index < (size_t)mTopIndex) 00685 return; 00686 // высчитывам положение строки 00687 int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop; 00688 // строка, после последнего видимого элемента 00689 if (_getClientWidget()->getHeight() < offset) 00690 return; 00691 00692 size_t index = _index - mTopIndex; 00693 if (index < mWidgetLines.size()) 00694 static_cast<Button*>(mWidgetLines[index])->setStateSelected(_select); 00695 00696 #if MYGUI_DEBUG_MODE == 1 00697 _checkMapping("ListBox::_selectIndex"); 00698 #endif 00699 } 00700 00701 void ListBox::beginToItemAt(size_t _index) 00702 { 00703 MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::beginToItemAt"); 00704 if (mRangeIndex <= 0) 00705 return; 00706 00707 int offset = (int)_index * mHeightLine; 00708 if (offset >= mRangeIndex) offset = mRangeIndex; 00709 00710 if (mWidgetScroll != nullptr) 00711 { 00712 if ((int)mWidgetScroll->getScrollPosition() == offset) 00713 return; 00714 mWidgetScroll->setScrollPosition(offset); 00715 } 00716 notifyScrollChangePosition(nullptr, offset); 00717 00718 #if MYGUI_DEBUG_MODE == 1 00719 _checkMapping("ListBox::beginToItemAt"); 00720 #endif 00721 } 00722 00723 // видим ли мы элемент, полностью или нет 00724 bool ListBox::isItemVisibleAt(size_t _index, bool _fill) 00725 { 00726 // если элемента нет, то мы его не видим (в том числе когда их вообще нет) 00727 if (_index >= mItemsInfo.size()) 00728 return false; 00729 // если скрола нет, то мы палюбак видим 00730 if (mRangeIndex <= 0) 00731 return true; 00732 00733 // строка, до первого видимого элемента 00734 if (_index < (size_t)mTopIndex) 00735 return false; 00736 00737 // строка это верхний выделенный 00738 if (_index == (size_t)mTopIndex) 00739 { 00740 if ((mOffsetTop != 0) && (_fill)) 00741 return false; // нам нужна полностью видимость 00742 return true; 00743 } 00744 00745 // высчитывам положение строки 00746 int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop; 00747 00748 // строка, после последнего видимого элемента 00749 if (_getClientWidget()->getHeight() < offset) 00750 return false; 00751 00752 // если мы внизу и нам нужен целый 00753 if ((_getClientWidget()->getHeight() < (offset + mHeightLine)) && (_fill)) 00754 return false; 00755 00756 return true; 00757 } 00758 00759 void ListBox::removeAllItems() 00760 { 00761 mTopIndex = 0; 00762 mIndexSelect = ITEM_NONE; 00763 mOffsetTop = 0; 00764 00765 mItemsInfo.clear(); 00766 00767 int offset = 0; 00768 for (size_t pos = 0; pos < mWidgetLines.size(); pos++) 00769 { 00770 mWidgetLines[pos]->setVisible(false); 00771 mWidgetLines[pos]->setPosition(0, offset); 00772 offset += mHeightLine; 00773 } 00774 00775 // обновляем все 00776 updateScroll(); 00777 updateLine(true); 00778 00779 #if MYGUI_DEBUG_MODE == 1 00780 _checkMapping("ListBox::removeAllItems"); 00781 #endif 00782 } 00783 00784 void ListBox::setItemNameAt(size_t _index, const UString& _name) 00785 { 00786 MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::setItemNameAt"); 00787 mItemsInfo[_index].first = _name; 00788 _redrawItem(_index); 00789 } 00790 00791 void ListBox::setItemDataAt(size_t _index, Any _data) 00792 { 00793 MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::setItemDataAt"); 00794 mItemsInfo[_index].second = _data; 00795 _redrawItem(_index); 00796 } 00797 00798 const UString& ListBox::getItemNameAt(size_t _index) 00799 { 00800 MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::getItemNameAt"); 00801 return mItemsInfo[_index].first; 00802 } 00803 00804 void ListBox::notifyMouseSetFocus(Widget* _sender, Widget* _old) 00805 { 00806 00807 #if MYGUI_DEBUG_MODE == 1 00808 MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>(), mWidgetLines.size(), "ListBox::notifyMouseSetFocus"); 00809 #endif 00810 00811 mLineActive = *_sender->_getInternalData<size_t>(); 00812 eventListMouseItemFocus(this, mLineActive); 00813 } 00814 00815 void ListBox::notifyMouseLostFocus(Widget* _sender, Widget* _new) 00816 { 00817 if ((nullptr == _new) || (_new->getParent() != _getClientWidget())) 00818 { 00819 mLineActive = ITEM_NONE; 00820 eventListMouseItemFocus(this, ITEM_NONE); 00821 } 00822 } 00823 00824 void ListBox::_setItemFocus(size_t _index, bool _focus) 00825 { 00826 MYGUI_ASSERT_RANGE(_index, mWidgetLines.size(), "ListBox::_setItemFocus"); 00827 static_cast<Button*>(mWidgetLines[_index])->_setMouseFocus(_focus); 00828 } 00829 00830 void ListBox::setScrollVisible(bool _visible) 00831 { 00832 if (mNeedVisibleScroll == _visible) 00833 return; 00834 mNeedVisibleScroll = _visible; 00835 updateScroll(); 00836 } 00837 00838 void ListBox::setScrollPosition(size_t _position) 00839 { 00840 if (mWidgetScroll != nullptr) 00841 { 00842 if (mWidgetScroll->getScrollRange() > _position) 00843 { 00844 mWidgetScroll->setScrollPosition(_position); 00845 _setScrollView(_position); 00846 } 00847 } 00848 } 00849 00850 void ListBox::_setScrollView(size_t _position) 00851 { 00852 mOffsetTop = ((int)_position % mHeightLine); 00853 00854 // смещение с отрицательной стороны 00855 int offset = 0 - mOffsetTop; 00856 00857 for (size_t pos = 0; pos < mWidgetLines.size(); pos++) 00858 { 00859 mWidgetLines[pos]->setPosition(IntPoint(0, offset)); 00860 offset += mHeightLine; 00861 } 00862 00863 // если индех изменился, то перерисовываем линии 00864 int top = ((int)_position / mHeightLine); 00865 if (top != mTopIndex) 00866 { 00867 mTopIndex = top; 00868 _redrawItemRange(); 00869 } 00870 00871 // прорисовываем все нижние строки, если они появились 00872 _redrawItemRange(mLastRedrawLine); 00873 } 00874 00875 void ListBox::_sendEventChangeScroll(size_t _position) 00876 { 00877 eventListChangeScroll(this, _position); 00878 if (ITEM_NONE != mLineActive) 00879 eventListMouseItemFocus(this, mLineActive); 00880 } 00881 00882 void ListBox::swapItemsAt(size_t _index1, size_t _index2) 00883 { 00884 MYGUI_ASSERT_RANGE(_index1, mItemsInfo.size(), "ListBox::swapItemsAt"); 00885 MYGUI_ASSERT_RANGE(_index2, mItemsInfo.size(), "ListBox::swapItemsAt"); 00886 00887 if (_index1 == _index2) 00888 return; 00889 00890 std::swap(mItemsInfo[_index1], mItemsInfo[_index2]); 00891 00892 _redrawItem(_index1); 00893 _redrawItem(_index2); 00894 } 00895 00896 void ListBox::_checkMapping(const std::string& _owner) 00897 { 00898 size_t count_pressed = 0; 00899 size_t count_show = 0; 00900 00901 for (size_t pos = 0; pos < mWidgetLines.size(); pos++) 00902 { 00903 MYGUI_ASSERT(pos == *mWidgetLines[pos]->_getInternalData<size_t>(), _owner); 00904 static_cast<Button*>(mWidgetLines[pos])->getStateSelected() ? count_pressed ++ : 0; 00905 static_cast<Button*>(mWidgetLines[pos])->getVisible() ? count_show ++ : 0; 00906 } 00907 //MYGUI_ASSERT(count_pressed < 2, _owner); 00908 //MYGUI_ASSERT((count_show + mOffsetTop) <= mItemsInfo.size(), _owner); 00909 } 00910 00911 void ListBox::_checkAlign() 00912 { 00913 // максимальная высота всех строк 00914 int max_height = mItemsInfo.size() * mHeightLine; 00915 // видимая высота 00916 int visible_height = _getClientWidget()->getHeight(); 00917 00918 // все строки помещаются 00919 if (visible_height >= max_height) 00920 { 00921 MYGUI_ASSERT(mTopIndex == 0, "mTopIndex == 0"); 00922 MYGUI_ASSERT(mOffsetTop == 0, "mOffsetTop == 0"); 00923 int height = 0; 00924 for (size_t pos = 0; pos < mWidgetLines.size(); pos++) 00925 { 00926 if (pos >= mItemsInfo.size()) 00927 break; 00928 MYGUI_ASSERT(mWidgetLines[pos]->getTop() == height, "mWidgetLines[pos]->getTop() == height"); 00929 height += mWidgetLines[pos]->getHeight(); 00930 } 00931 } 00932 } 00933 00934 size_t ListBox::findItemIndexWith(const UString& _name) 00935 { 00936 for (size_t pos = 0; pos < mItemsInfo.size(); pos++) 00937 { 00938 if (mItemsInfo[pos].first == _name) 00939 return pos; 00940 } 00941 return ITEM_NONE; 00942 } 00943 00944 int ListBox::getOptimalHeight() 00945 { 00946 return (int)((mCoord.height - _getClientWidget()->getHeight()) + (mItemsInfo.size() * mHeightLine)); 00947 } 00948 00949 Widget* ListBox::_getClientWidget() 00950 { 00951 return mClient == nullptr ? this : mClient; 00952 } 00953 00954 size_t ListBox::getItemCount() const 00955 { 00956 return mItemsInfo.size(); 00957 } 00958 00959 void ListBox::addItem(const UString& _name, Any _data) 00960 { 00961 insertItemAt(ITEM_NONE, _name, _data); 00962 } 00963 00964 size_t ListBox::getIndexSelected() const 00965 { 00966 return mIndexSelect; 00967 } 00968 00969 void ListBox::clearIndexSelected() 00970 { 00971 setIndexSelected(ITEM_NONE); 00972 } 00973 00974 void ListBox::clearItemDataAt(size_t _index) 00975 { 00976 setItemDataAt(_index, Any::Null); 00977 } 00978 00979 void ListBox::beginToItemFirst() 00980 { 00981 if (getItemCount()) 00982 beginToItemAt(0); 00983 } 00984 00985 void ListBox::beginToItemLast() 00986 { 00987 if (getItemCount()) 00988 beginToItemAt(getItemCount() - 1); 00989 } 00990 00991 void ListBox::beginToItemSelected() 00992 { 00993 if (getIndexSelected() != ITEM_NONE) 00994 beginToItemAt(getIndexSelected()); 00995 } 00996 00997 bool ListBox::isItemSelectedVisible(bool _fill) 00998 { 00999 return isItemVisibleAt(mIndexSelect, _fill); 01000 } 01001 01002 void ListBox::setPosition(int _left, int _top) 01003 { 01004 setPosition(IntPoint(_left, _top)); 01005 } 01006 01007 void ListBox::setSize(int _width, int _height) 01008 { 01009 setSize(IntSize(_width, _height)); 01010 } 01011 01012 void ListBox::setCoord(int _left, int _top, int _width, int _height) 01013 { 01014 setCoord(IntCoord(_left, _top, _width, _height)); 01015 } 01016 01017 size_t ListBox::_getItemIndex(Widget* _item) 01018 { 01019 for (VectorButton::iterator iter = mWidgetLines.begin(); iter != mWidgetLines.end(); ++iter) 01020 { 01021 if ((*iter) == _item) 01022 return *(*iter)->_getInternalData<size_t>() + mTopIndex; 01023 } 01024 return ITEM_NONE; 01025 } 01026 01027 void ListBox::_resetContainer(bool _update) 01028 { 01029 // обязательно у базового 01030 Base::_resetContainer(_update); 01031 01032 if (!_update) 01033 { 01034 WidgetManager& instance = WidgetManager::getInstance(); 01035 for (VectorButton::iterator iter = mWidgetLines.begin(); iter != mWidgetLines.end(); ++iter) 01036 instance.unlinkFromUnlinkers(*iter); 01037 } 01038 } 01039 01040 void ListBox::setPropertyOverride(const std::string& _key, const std::string& _value) 01041 { 01042 if (_key == "AddItem") 01043 addItem(_value); 01044 else 01045 { 01046 Base::setPropertyOverride(_key, _value); 01047 return; 01048 } 01049 eventChangeProperty(this, _key, _value); 01050 } 01051 01052 size_t ListBox::_getItemCount() 01053 { 01054 return getItemCount(); 01055 } 01056 01057 void ListBox::_addItem(const MyGUI::UString& _name) 01058 { 01059 addItem(_name); 01060 } 01061 01062 void ListBox::_removeItemAt(size_t _index) 01063 { 01064 removeItemAt(_index); 01065 } 01066 01067 void ListBox::_setItemNameAt(size_t _index, const UString& _name) 01068 { 01069 setItemNameAt(_index, _name); 01070 } 01071 01072 const UString& ListBox::_getItemNameAt(size_t _index) 01073 { 01074 return getItemNameAt(_index); 01075 } 01076 01077 } // namespace MyGUI