MyGUI  3.2.1
MyGUI_ListBox.cpp
Go to the documentation of this file.
1 /*
2  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3  * Distributed under the MIT License
4  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5  */
6 
7 #include "MyGUI_Precompiled.h"
8 #include "MyGUI_ListBox.h"
9 #include "MyGUI_Button.h"
10 #include "MyGUI_ScrollBar.h"
11 #include "MyGUI_ResourceSkin.h"
12 #include "MyGUI_InputManager.h"
13 #include "MyGUI_WidgetManager.h"
14 
15 namespace MyGUI
16 {
17 
19  mWidgetScroll(nullptr),
20  mHeightLine(1),
21  mTopIndex(0),
22  mOffsetTop(0),
23  mRangeIndex(-1),
24  mLastRedrawLine(0),
25  mIndexSelect(ITEM_NONE),
26  mLineActive(ITEM_NONE),
27  mNeedVisibleScroll(true),
28  mClient(nullptr)
29  {
30  }
31 
33  {
34  Base::initialiseOverride();
35 
36  // FIXME нам нужен фокус клавы
37  setNeedKeyFocus(true);
38 
39  // парсим свойства
40  if (isUserString("SkinLine"))
41  mSkinLine = getUserString("SkinLine");
42 
43  if (isUserString("HeightLine"))
44  mHeightLine = utility::parseInt(getUserString("HeightLine"));
45 
46  if (mHeightLine < 1)
47  mHeightLine = 1;
48 
50  assignWidget(mClient, "Client");
51  if (mClient != nullptr)
52  {
57  setWidgetClient(mClient);
58  }
59 
61  assignWidget(mWidgetScroll, "VScroll");
62  if (mWidgetScroll != nullptr)
63  {
65  mWidgetScroll->setScrollPage((size_t)mHeightLine);
66  mWidgetScroll->setScrollViewPage((size_t)mHeightLine);
67  }
68 
69  updateScroll();
70  updateLine();
71  }
72 
74  {
75  mWidgetScroll = nullptr;
76  mClient = nullptr;
77 
78  Base::shutdownOverride();
79  }
80 
81  void ListBox::onMouseWheel(int _rel)
82  {
83  notifyMouseWheel(nullptr, _rel);
84 
85  Base::onMouseWheel(_rel);
86  }
87 
89  {
90  if (getItemCount() == 0)
91  {
92  Base::onKeyButtonPressed(_key, _char);
94  return;
95  }
96 
97  // очень секретный метод, запатентованный механизм движения курсора
98  size_t sel = mIndexSelect;
99 
100  if (_key == KeyCode::ArrowUp)
101  {
102  if (sel != 0)
103  {
104  if (sel == ITEM_NONE)
105  sel = 0;
106  else
107  sel --;
108  }
109  }
110  else if (_key == KeyCode::ArrowDown)
111  {
112  if (sel == ITEM_NONE)
113  sel = 0;
114  else
115  sel ++;
116 
117  if (sel >= getItemCount())
118  {
119  // старое значение
120  sel = mIndexSelect;
121  }
122  }
123  else if (_key == KeyCode::Home)
124  {
125  if (sel != 0)
126  sel = 0;
127  }
128  else if (_key == KeyCode::End)
129  {
130  if (sel != (getItemCount() - 1))
131  {
132  sel = getItemCount() - 1;
133  }
134  }
135  else if (_key == KeyCode::PageUp)
136  {
137  if (sel != 0)
138  {
139  if (sel == ITEM_NONE)
140  {
141  sel = 0;
142  }
143  else
144  {
145  size_t page = _getClientWidget()->getHeight() / mHeightLine;
146  if (sel <= page)
147  sel = 0;
148  else
149  sel -= page;
150  }
151  }
152  }
153  else if (_key == KeyCode::PageDown)
154  {
155  if (sel != (getItemCount() - 1))
156  {
157  if (sel == ITEM_NONE)
158  {
159  sel = 0;
160  }
161  else
162  {
163  sel += _getClientWidget()->getHeight() / mHeightLine;
164  if (sel >= getItemCount())
165  sel = getItemCount() - 1;
166  }
167  }
168  }
169  else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
170  {
171  if (sel != ITEM_NONE)
172  {
173  //FIXME нас могут удалить
174  eventListSelectAccept(this, sel);
175 
176  Base::onKeyButtonPressed(_key, _char);
177 
179  // выходим, так как изменили колличество строк
180  return;
181  }
182  }
183 
184  if (sel != mIndexSelect)
185  {
186  _resetContainer(true);
187 
188  if (!isItemVisibleAt(sel))
189  {
190  beginToItemAt(sel);
191  if (mWidgetScroll != nullptr)
192  _sendEventChangeScroll(mWidgetScroll->getScrollPosition());
193  }
194  setIndexSelected(sel);
195 
196  // изменилась позиция
197  // FIXME нас могут удалить
198  eventListChangePosition(this, mIndexSelect);
199  }
200 
201  Base::onKeyButtonPressed(_key, _char);
203  }
204 
205  void ListBox::notifyMouseWheel(Widget* _sender, int _rel)
206  {
207  if (mRangeIndex <= 0)
208  return;
209 
210  if (mWidgetScroll == nullptr)
211  return;
212 
213  int offset = (int)mWidgetScroll->getScrollPosition();
214  if (_rel < 0)
215  offset += mHeightLine;
216  else
217  offset -= mHeightLine;
218 
219  if (offset >= mRangeIndex)
220  offset = mRangeIndex;
221  else if (offset < 0)
222  offset = 0;
223 
224  if ((int)mWidgetScroll->getScrollPosition() == offset)
225  return;
226 
227  mWidgetScroll->setScrollPosition(offset);
228  _setScrollView(offset);
229  _sendEventChangeScroll(offset);
230 
231  _resetContainer(true);
232  }
233 
234  void ListBox::notifyScrollChangePosition(ScrollBar* _sender, size_t _position)
235  {
236  _setScrollView(_position);
237  _sendEventChangeScroll(_position);
238  }
239 
240  void ListBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
241  {
242  if (MouseButton::Left == _id)
243  {
244  // если выделен клиент, то сбрасываем
245  if (_sender == _getClientWidget())
246  {
247  if (mIndexSelect != ITEM_NONE)
248  {
249  _selectIndex(mIndexSelect, false);
250  mIndexSelect = ITEM_NONE;
251  eventListChangePosition(this, mIndexSelect);
252  }
253  eventListMouseItemActivate(this, mIndexSelect);
254 
255  // если не клиент, то просчитывам
256  }
257  // ячейка может быть скрыта
258  else if (_sender->getVisible())
259  {
260 
261 #if MYGUI_DEBUG_MODE == 1
262  _checkMapping("ListBox::notifyMousePressed");
263  MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>(), mWidgetLines.size(), "ListBox::notifyMousePressed");
264  MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>() + mTopIndex, mItemsInfo.size(), "ListBox::notifyMousePressed");
265 #endif
266 
267  size_t index = *_sender->_getInternalData<size_t>() + mTopIndex;
268 
269  if (mIndexSelect != index)
270  {
271  _selectIndex(mIndexSelect, false);
272  _selectIndex(index, true);
273  mIndexSelect = index;
274  eventListChangePosition(this, mIndexSelect);
275  }
276  eventListMouseItemActivate(this, mIndexSelect);
277  }
278 
279  _resetContainer(true);
280  }
281 
282  eventNotifyItem(this, IBNotifyItemData(getIndexByWidget(_sender), IBNotifyItemData::MousePressed, _left, _top, _id));
283  }
284 
286  {
287  if (mIndexSelect != ITEM_NONE)
288  eventListSelectAccept(this, mIndexSelect);
289  }
290 
291  void ListBox::setPosition(const IntPoint& _point)
292  {
293  Base::setPosition(_point);
294  }
295 
296  void ListBox::setSize(const IntSize& _size)
297  {
298  Base::setSize(_size);
299 
300  updateScroll();
301  updateLine();
302  }
303 
304  void ListBox::setCoord(const IntCoord& _coord)
305  {
306  Base::setCoord(_coord);
307 
308  updateScroll();
309  updateLine();
310  }
311 
313  {
314  mRangeIndex = (mHeightLine * (int)mItemsInfo.size()) - _getClientWidget()->getHeight();
315 
316  if (mWidgetScroll == nullptr)
317  return;
318 
319  if ((!mNeedVisibleScroll) || (mRangeIndex < 1) || (mWidgetScroll->getLeft() <= _getClientWidget()->getLeft()))
320  {
321  if (mWidgetScroll->getVisible())
322  {
323  mWidgetScroll->setVisible(false);
324  // увеличиваем клиентскую зону на ширину скрола
325  if (mClient != nullptr)
326  mClient->setSize(mClient->getWidth() + mWidgetScroll->getWidth(), mClient->getHeight());
327  }
328  }
329  else if (!mWidgetScroll->getVisible())
330  {
331  if (mClient != nullptr)
332  mClient->setSize(mClient->getWidth() - mWidgetScroll->getWidth(), mClient->getHeight());
333  mWidgetScroll->setVisible(true);
334  }
335 
336  mWidgetScroll->setScrollRange(mRangeIndex + 1);
337  if (!mItemsInfo.empty())
338  mWidgetScroll->setTrackSize(mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size());
339  }
340 
341  void ListBox::updateLine(bool _reset)
342  {
343  // сбрасываем
344  if (_reset)
345  {
346  mOldSize.clear();
347  mLastRedrawLine = 0;
348  _resetContainer(false);
349  }
350 
351  // позиция скролла
352  int position = mTopIndex * mHeightLine + mOffsetTop;
353 
354  // если высота увеличивалась то добавляем виджеты
355  if (mOldSize.height < mCoord.height)
356  {
357  int height = (int)mWidgetLines.size() * mHeightLine - mOffsetTop;
358 
359  // до тех пор, пока не достигнем максимального колличества, и всегда на одну больше
360  while ( (height <= (_getClientWidget()->getHeight() + mHeightLine)) && (mWidgetLines.size() < mItemsInfo.size()) )
361  {
362  // создаем линию
363  Widget* widget = _getClientWidget()->createWidgetT("Button", mSkinLine, 0, height, _getClientWidget()->getWidth(), mHeightLine, Align::Top | Align::HStretch);
364  Button* line = widget->castType<Button>();
365  // подписываемся на всякие там события
374  line->_setContainer(this);
375  // присваиваем порядковый номер, для простоты просчета
376  line->_setInternalData((size_t)mWidgetLines.size());
377  // и сохраняем
378  mWidgetLines.push_back(line);
379  height += mHeightLine;
380  }
381 
382  // проверяем на возможность не менять положение списка
383  if (position >= mRangeIndex)
384  {
385  // размер всех помещается в клиент
386  if (mRangeIndex <= 0)
387  {
388  // обнуляем, если надо
389  if (position || mOffsetTop || mTopIndex)
390  {
391  position = 0;
392  mTopIndex = 0;
393  mOffsetTop = 0;
394  mLastRedrawLine = 0; // чтобы все перерисовалось
395 
396  // выравниваем
397  int offset = 0;
398  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
399  {
400  mWidgetLines[pos]->setPosition(0, offset);
401  offset += mHeightLine;
402  }
403  }
404  }
405  else
406  {
407  // прижимаем список к нижней границе
408  int count = _getClientWidget()->getHeight() / mHeightLine;
409  mOffsetTop = mHeightLine - (_getClientWidget()->getHeight() % mHeightLine);
410 
411  if (mOffsetTop == mHeightLine)
412  {
413  mOffsetTop = 0;
414  count --;
415  }
416 
417  int top = (int)mItemsInfo.size() - count - 1;
418 
419  // выравниваем
420  int offset = 0 - mOffsetTop;
421  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
422  {
423  mWidgetLines[pos]->setPosition(0, offset);
424  offset += mHeightLine;
425  }
426 
427  // высчитываем положение, должно быть максимальным
428  position = top * mHeightLine + mOffsetTop;
429 
430  // если индех изменился, то перерисовываем линии
431  if (top != mTopIndex)
432  {
433  mTopIndex = top;
435  }
436  }
437  }
438 
439  // увеличился размер, но прокрутки вниз небыло, обновляем линии снизу
440  _redrawItemRange(mLastRedrawLine);
441 
442  } // if (old_cy < mCoord.height)
443 
444  // просчитываем положение скролла
445  if (mWidgetScroll != nullptr)
446  mWidgetScroll->setScrollPosition(position);
447 
448  mOldSize.width = mCoord.width;
449  mOldSize.height = mCoord.height;
450 
451 #if MYGUI_DEBUG_MODE == 1
452  _checkMapping("ListBox::updateLine");
453 #endif
454  }
455 
456  void ListBox::_redrawItemRange(size_t _start)
457  {
458  // перерисовываем линии, только те, что видны
459  size_t pos = _start;
460  for (; pos < mWidgetLines.size(); pos++)
461  {
462  // индекс в нашем массиве
463  size_t index = pos + (size_t)mTopIndex;
464 
465  // не будем заходить слишком далеко
466  if (index >= mItemsInfo.size())
467  {
468  // запоминаем последнюю перерисованную линию
469  mLastRedrawLine = pos;
470  break;
471  }
472  if (mWidgetLines[pos]->getTop() > _getClientWidget()->getHeight())
473  {
474  // запоминаем последнюю перерисованную линию
475  mLastRedrawLine = pos;
476  break;
477  }
478 
479  // если был скрыт, то покажем
480  mWidgetLines[pos]->setVisible(true);
481  // обновляем текст
482  mWidgetLines[pos]->setCaption(mItemsInfo[index].first);
483 
484  // если нужно выделить ,то выделим
485  static_cast<Button*>(mWidgetLines[pos])->setStateSelected(index == mIndexSelect);
486  }
487 
488  // если цикл весь прошли, то ставим максимальную линию
489  if (pos >= mWidgetLines.size())
490  {
491  mLastRedrawLine = pos;
492  }
493  else
494  {
495  //Widget* focus = InputManager::getInstance().getMouseFocusWidget();
496  for (; pos < mWidgetLines.size(); pos++)
497  {
498  static_cast<Button*>(mWidgetLines[pos])->setStateSelected(false);
499  static_cast<Button*>(mWidgetLines[pos])->setVisible(false);
500  //if (focus == mWidgetLines[pos]) InputManager::getInstance()._unlinkWidget(focus);
501  }
502  }
503 
504 #if MYGUI_DEBUG_MODE == 1
505  _checkMapping("ListBox::_redrawItemRange");
506 #endif
507  }
508 
509  // перерисовывает индекс
510  void ListBox::_redrawItem(size_t _index)
511  {
512  // невидно
513  if (_index < (size_t)mTopIndex)
514  return;
515  _index -= (size_t)mTopIndex;
516  // тоже невидно
517  if (_index >= mLastRedrawLine)
518  return;
519 
520  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::_redrawItem");
521  // перерисовываем
522  mWidgetLines[_index]->setCaption(mItemsInfo[_index + mTopIndex].first);
523 
524 #if MYGUI_DEBUG_MODE == 1
525  _checkMapping("ListBox::_redrawItem");
526 #endif
527  }
528 
529  void ListBox::insertItemAt(size_t _index, const UString& _name, Any _data)
530  {
531  MYGUI_ASSERT_RANGE_INSERT(_index, mItemsInfo.size(), "ListBox::insertItemAt");
532  if (_index == ITEM_NONE)
533  _index = mItemsInfo.size();
534 
535  // вставляем физически
536  mItemsInfo.insert(mItemsInfo.begin() + _index, PairItem(_name, _data));
537 
538  // если надо, то меняем выделенный элемент
539  if ((mIndexSelect != ITEM_NONE) && (_index <= mIndexSelect))
540  mIndexSelect++;
541 
542  // строка, до первого видимого элемента
543  if ((_index <= (size_t)mTopIndex) && (mRangeIndex > 0))
544  {
545  mTopIndex ++;
546  // просчитываем положение скролла
547  if (mWidgetScroll != nullptr)
548  {
549  mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() + mHeightLine);
550  if (!mItemsInfo.empty())
551  mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() );
552  mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
553  }
554  mRangeIndex += mHeightLine;
555  }
556  else
557  {
558  // высчитывам положение строки
559  int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
560 
561  // строка, после последнего видимого элемента, плюс одна строка (потому что для прокрутки нужно на одну строчку больше)
562  if (_getClientWidget()->getHeight() < (offset - mHeightLine))
563  {
564  // просчитываем положение скролла
565  if (mWidgetScroll != nullptr)
566  {
567  mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() + mHeightLine);
568  if (!mItemsInfo.empty())
569  mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() );
570  mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
571  }
572  mRangeIndex += mHeightLine;
573 
574  // строка в видимой области
575  }
576  else
577  {
578  // обновляем все
579  updateScroll();
580  updateLine(true);
581 
582  // позже сюда еще оптимизацию по колличеству перерисовок
583  }
584  }
585 
586 #if MYGUI_DEBUG_MODE == 1
587  _checkMapping("ListBox::insertItemAt");
588 #endif
589  }
590 
591  void ListBox::removeItemAt(size_t _index)
592  {
593  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::removeItemAt");
594 
595  // удяляем физически строку
596  mItemsInfo.erase(mItemsInfo.begin() + _index);
597 
598  // если надо, то меняем выделенный элемент
599  if (mItemsInfo.empty()) mIndexSelect = ITEM_NONE;
600  else if (mIndexSelect != ITEM_NONE)
601  {
602  if (_index < mIndexSelect)
603  mIndexSelect--;
604  else if ((_index == mIndexSelect) && (mIndexSelect == (mItemsInfo.size())))
605  mIndexSelect--;
606  }
607 
608  // если виджетов стало больше , то скрываем крайний
609  if (mWidgetLines.size() > mItemsInfo.size())
610  {
611  mWidgetLines[mItemsInfo.size()]->setVisible(false);
612  }
613 
614  // строка, до первого видимого элемента
615  if (_index < (size_t)mTopIndex)
616  {
617  mTopIndex --;
618  // просчитываем положение скролла
619  if (mWidgetScroll != nullptr)
620  {
621  mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() - mHeightLine);
622  if (!mItemsInfo.empty())
623  mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() );
624  mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
625  }
626  mRangeIndex -= mHeightLine;
627  }
628  else
629  {
630  // высчитывам положение удаляемой строки
631  int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
632 
633  // строка, после последнего видимого элемента
634  if (_getClientWidget()->getHeight() < offset)
635  {
636  // просчитываем положение скролла
637  if (mWidgetScroll != nullptr)
638  {
639  mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() - mHeightLine);
640  if (!mItemsInfo.empty())
641  mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() );
642  mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
643  }
644  mRangeIndex -= mHeightLine;
645 
646  // строка в видимой области
647  }
648  else
649  {
650  // обновляем все
651  updateScroll();
652  updateLine(true);
653 
654  // позже сюда еще оптимизацию по колличеству перерисовок
655  }
656  }
657 
658 #if MYGUI_DEBUG_MODE == 1
659  _checkMapping("ListBox::removeItemAt");
660 #endif
661  }
662 
663  void ListBox::setIndexSelected(size_t _index)
664  {
665  MYGUI_ASSERT_RANGE_AND_NONE(_index, mItemsInfo.size(), "ListBox::setIndexSelected");
666  if (mIndexSelect != _index)
667  {
668  _selectIndex(mIndexSelect, false);
669  _selectIndex(_index, true);
670  mIndexSelect = _index;
671  }
672  }
673 
674  void ListBox::_selectIndex(size_t _index, bool _select)
675  {
676  if (_index == ITEM_NONE)
677  return;
678  // не видно строки
679  if (_index < (size_t)mTopIndex)
680  return;
681  // высчитывам положение строки
682  int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
683  // строка, после последнего видимого элемента
684  if (_getClientWidget()->getHeight() < offset)
685  return;
686 
687  size_t index = _index - mTopIndex;
688  if (index < mWidgetLines.size())
689  static_cast<Button*>(mWidgetLines[index])->setStateSelected(_select);
690 
691 #if MYGUI_DEBUG_MODE == 1
692  _checkMapping("ListBox::_selectIndex");
693 #endif
694  }
695 
696  void ListBox::beginToItemAt(size_t _index)
697  {
698  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::beginToItemAt");
699  if (mRangeIndex <= 0)
700  return;
701 
702  int offset = (int)_index * mHeightLine;
703  if (offset >= mRangeIndex) offset = mRangeIndex;
704 
705  if (mWidgetScroll != nullptr)
706  {
707  if ((int)mWidgetScroll->getScrollPosition() == offset)
708  return;
709  mWidgetScroll->setScrollPosition(offset);
710  }
711  notifyScrollChangePosition(nullptr, offset);
712 
713 #if MYGUI_DEBUG_MODE == 1
714  _checkMapping("ListBox::beginToItemAt");
715 #endif
716  }
717 
718  // видим ли мы элемент, полностью или нет
719  bool ListBox::isItemVisibleAt(size_t _index, bool _fill)
720  {
721  // если элемента нет, то мы его не видим (в том числе когда их вообще нет)
722  if (_index >= mItemsInfo.size())
723  return false;
724  // если скрола нет, то мы палюбак видим
725  if (mRangeIndex <= 0)
726  return true;
727 
728  // строка, до первого видимого элемента
729  if (_index < (size_t)mTopIndex)
730  return false;
731 
732  // строка это верхний выделенный
733  if (_index == (size_t)mTopIndex)
734  {
735  if ((mOffsetTop != 0) && (_fill))
736  return false; // нам нужна полностью видимость
737  return true;
738  }
739 
740  // высчитывам положение строки
741  int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
742 
743  // строка, после последнего видимого элемента
744  if (_getClientWidget()->getHeight() < offset)
745  return false;
746 
747  // если мы внизу и нам нужен целый
748  if ((_getClientWidget()->getHeight() < (offset + mHeightLine)) && (_fill))
749  return false;
750 
751  return true;
752  }
753 
755  {
756  mTopIndex = 0;
757  mIndexSelect = ITEM_NONE;
758  mOffsetTop = 0;
759 
760  mItemsInfo.clear();
761 
762  int offset = 0;
763  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
764  {
765  mWidgetLines[pos]->setVisible(false);
766  mWidgetLines[pos]->setPosition(0, offset);
767  offset += mHeightLine;
768  }
769 
770  // обновляем все
771  updateScroll();
772  updateLine(true);
773 
774 #if MYGUI_DEBUG_MODE == 1
775  _checkMapping("ListBox::removeAllItems");
776 #endif
777  }
778 
779  void ListBox::setItemNameAt(size_t _index, const UString& _name)
780  {
781  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::setItemNameAt");
782  mItemsInfo[_index].first = _name;
783  _redrawItem(_index);
784  }
785 
786  void ListBox::setItemDataAt(size_t _index, Any _data)
787  {
788  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::setItemDataAt");
789  mItemsInfo[_index].second = _data;
790  _redrawItem(_index);
791  }
792 
793  const UString& ListBox::getItemNameAt(size_t _index)
794  {
795  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::getItemNameAt");
796  return mItemsInfo[_index].first;
797  }
798 
800  {
801 
802 #if MYGUI_DEBUG_MODE == 1
803  MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>(), mWidgetLines.size(), "ListBox::notifyMouseSetFocus");
804 #endif
805 
806  mLineActive = *_sender->_getInternalData<size_t>();
807  eventListMouseItemFocus(this, mLineActive);
808  }
809 
811  {
812  if ((nullptr == _new) || (_new->getParent() != _getClientWidget()))
813  {
814  mLineActive = ITEM_NONE;
816  }
817  }
818 
819  void ListBox::_setItemFocus(size_t _index, bool _focus)
820  {
821  MYGUI_ASSERT_RANGE(_index, mWidgetLines.size(), "ListBox::_setItemFocus");
822  static_cast<Button*>(mWidgetLines[_index])->_setMouseFocus(_focus);
823  }
824 
825  void ListBox::setScrollVisible(bool _visible)
826  {
827  if (mNeedVisibleScroll == _visible)
828  return;
829  mNeedVisibleScroll = _visible;
830  updateScroll();
831  }
832 
833  void ListBox::setScrollPosition(size_t _position)
834  {
835  if (mWidgetScroll != nullptr)
836  {
837  if (mWidgetScroll->getScrollRange() > _position)
838  {
839  mWidgetScroll->setScrollPosition(_position);
840  _setScrollView(_position);
841  }
842  }
843  }
844 
845  void ListBox::_setScrollView(size_t _position)
846  {
847  mOffsetTop = ((int)_position % mHeightLine);
848 
849  // смещение с отрицательной стороны
850  int offset = 0 - mOffsetTop;
851 
852  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
853  {
854  mWidgetLines[pos]->setPosition(IntPoint(0, offset));
855  offset += mHeightLine;
856  }
857 
858  // если индех изменился, то перерисовываем линии
859  int top = ((int)_position / mHeightLine);
860  if (top != mTopIndex)
861  {
862  mTopIndex = top;
864  }
865 
866  // прорисовываем все нижние строки, если они появились
867  _redrawItemRange(mLastRedrawLine);
868  }
869 
870  void ListBox::_sendEventChangeScroll(size_t _position)
871  {
872  eventListChangeScroll(this, _position);
873  if (ITEM_NONE != mLineActive)
874  eventListMouseItemFocus(this, mLineActive);
875  }
876 
877  void ListBox::swapItemsAt(size_t _index1, size_t _index2)
878  {
879  MYGUI_ASSERT_RANGE(_index1, mItemsInfo.size(), "ListBox::swapItemsAt");
880  MYGUI_ASSERT_RANGE(_index2, mItemsInfo.size(), "ListBox::swapItemsAt");
881 
882  if (_index1 == _index2)
883  return;
884 
885  std::swap(mItemsInfo[_index1], mItemsInfo[_index2]);
886 
887  _redrawItem(_index1);
888  _redrawItem(_index2);
889  }
890 
891  void ListBox::_checkMapping(const std::string& _owner)
892  {
893  size_t count_pressed = 0;
894  size_t count_show = 0;
895 
896  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
897  {
898  MYGUI_ASSERT(pos == *mWidgetLines[pos]->_getInternalData<size_t>(), _owner);
899  if (static_cast<Button*>(mWidgetLines[pos])->getStateSelected())
900  count_pressed ++;
901  if (static_cast<Button*>(mWidgetLines[pos])->getVisible())
902  count_show ++;
903  }
904  //MYGUI_ASSERT(count_pressed < 2, _owner);
905  //MYGUI_ASSERT((count_show + mOffsetTop) <= mItemsInfo.size(), _owner);
906  }
907 
909  {
910  // максимальная высота всех строк
911  int max_height = mItemsInfo.size() * mHeightLine;
912  // видимая высота
913  int visible_height = _getClientWidget()->getHeight();
914 
915  // все строки помещаются
916  if (visible_height >= max_height)
917  {
918  MYGUI_ASSERT(mTopIndex == 0, "mTopIndex == 0");
919  MYGUI_ASSERT(mOffsetTop == 0, "mOffsetTop == 0");
920  int height = 0;
921  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
922  {
923  if (pos >= mItemsInfo.size())
924  break;
925  MYGUI_ASSERT(mWidgetLines[pos]->getTop() == height, "mWidgetLines[pos]->getTop() == height");
926  height += mWidgetLines[pos]->getHeight();
927  }
928  }
929  }
930 
931  size_t ListBox::findItemIndexWith(const UString& _name)
932  {
933  for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
934  {
935  if (mItemsInfo[pos].first == _name)
936  return pos;
937  }
938  return ITEM_NONE;
939  }
940 
942  {
943  return (int)((mCoord.height - _getClientWidget()->getHeight()) + (mItemsInfo.size() * mHeightLine));
944  }
945 
946  Widget* ListBox::_getClientWidget()
947  {
948  return mClient == nullptr ? this : mClient;
949  }
950 
951  size_t ListBox::getItemCount() const
952  {
953  return mItemsInfo.size();
954  }
955 
956  void ListBox::addItem(const UString& _name, Any _data)
957  {
958  insertItemAt(ITEM_NONE, _name, _data);
959  }
960 
962  {
963  return mIndexSelect;
964  }
965 
967  {
969  }
970 
971  void ListBox::clearItemDataAt(size_t _index)
972  {
973  setItemDataAt(_index, Any::Null);
974  }
975 
977  {
978  if (getItemCount())
979  beginToItemAt(0);
980  }
981 
983  {
984  if (getItemCount())
986  }
987 
989  {
990  if (getIndexSelected() != ITEM_NONE)
992  }
993 
995  {
996  return isItemVisibleAt(mIndexSelect, _fill);
997  }
998 
999  void ListBox::setPosition(int _left, int _top)
1000  {
1001  setPosition(IntPoint(_left, _top));
1002  }
1003 
1004  void ListBox::setSize(int _width, int _height)
1005  {
1006  setSize(IntSize(_width, _height));
1007  }
1008 
1009  void ListBox::setCoord(int _left, int _top, int _width, int _height)
1010  {
1011  setCoord(IntCoord(_left, _top, _width, _height));
1012  }
1013 
1015  {
1016  for (VectorButton::iterator iter = mWidgetLines.begin(); iter != mWidgetLines.end(); ++iter)
1017  {
1018  if ((*iter) == _item)
1019  return *(*iter)->_getInternalData<size_t>() + mTopIndex;
1020  }
1021  return ITEM_NONE;
1022  }
1023 
1024  void ListBox::_resetContainer(bool _update)
1025  {
1026  // обязательно у базового
1027  Base::_resetContainer(_update);
1028 
1029  if (!_update)
1030  {
1032  for (VectorButton::iterator iter = mWidgetLines.begin(); iter != mWidgetLines.end(); ++iter)
1033  instance.unlinkFromUnlinkers(*iter);
1034  }
1035  }
1036 
1037  void ListBox::setPropertyOverride(const std::string& _key, const std::string& _value)
1038  {
1039  // не коментировать
1040  if (_key == "AddItem")
1041  addItem(_value);
1042 
1043  else
1044  {
1045  Base::setPropertyOverride(_key, _value);
1046  return;
1047  }
1048 
1049  eventChangeProperty(this, _key, _value);
1050  }
1051 
1053  {
1054  return getItemCount();
1055  }
1056 
1058  {
1059  addItem(_name);
1060  }
1061 
1062  void ListBox::_removeItemAt(size_t _index)
1063  {
1064  removeItemAt(_index);
1065  }
1066 
1067  void ListBox::_setItemNameAt(size_t _index, const UString& _name)
1068  {
1069  setItemNameAt(_index, _name);
1070  }
1071 
1072  const UString& ListBox::_getItemNameAt(size_t _index)
1073  {
1074  return getItemNameAt(_index);
1075  }
1076 
1077  size_t ListBox::getIndexByWidget(Widget* _widget)
1078  {
1079  if (_widget == mClient)
1080  return ITEM_NONE;
1081  return *_widget->_getInternalData<size_t>() + mTopIndex;
1082  }
1083 
1085  {
1086  eventNotifyItem(this, IBNotifyItemData(getIndexByWidget(_sender), IBNotifyItemData::KeyPressed, _key, _char));
1087  }
1088 
1090  {
1091  eventNotifyItem(this, IBNotifyItemData(getIndexByWidget(_sender), IBNotifyItemData::KeyReleased, _key));
1092  }
1093 
1094  void ListBox::notifyMouseButtonReleased(Widget* _sender, int _left, int _top, MouseButton _id)
1095  {
1096  eventNotifyItem(this, IBNotifyItemData(getIndexByWidget(_sender), IBNotifyItemData::MouseReleased, _left, _top, _id));
1097  }
1098 
1100  {
1101  Base::onKeyButtonReleased(_key);
1102 
1104  }
1105 
1107  {
1108  if (_index == MyGUI::ITEM_NONE)
1109  return nullptr;
1110 
1111  // индекс в нашем массиве
1112  size_t index = _index + (size_t)mTopIndex;
1113 
1114  if (index < mWidgetLines.size())
1115  return mWidgetLines[index];
1116  return nullptr;
1117  }
1118 
1119 } // namespace MyGUI