MyGUI  3.4.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  mActivateOnClick(false),
21  mHeightLine(1),
22  mTopIndex(0),
23  mOffsetTop(0),
24  mRangeIndex(-1),
25  mLastRedrawLine(0),
26  mIndexSelect(ITEM_NONE),
27  mLineActive(ITEM_NONE),
28  mNeedVisibleScroll(true)
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 
49  if (getClientWidget() != nullptr)
50  {
55  }
56 
58  assignWidget(mWidgetScroll, "VScroll");
59  if (mWidgetScroll != nullptr)
60  {
62  mWidgetScroll->setScrollPage((size_t)mHeightLine);
63  }
64 
65  updateScroll();
66  updateLine();
67  }
68 
70  {
71  mWidgetScroll = nullptr;
72 
73  Base::shutdownOverride();
74  }
75 
76  void ListBox::onMouseWheel(int _rel)
77  {
78  notifyMouseWheel(nullptr, _rel);
79 
80  Base::onMouseWheel(_rel);
81  }
82 
84  {
85  if (getItemCount() == 0)
86  {
87  Base::onKeyButtonPressed(_key, _char);
89  return;
90  }
91 
92  // очень секретный метод, запатентованный механизм движения курсора
93  size_t sel = mIndexSelect;
94 
95  if (_key == KeyCode::ArrowUp)
96  {
97  if (sel != 0)
98  {
99  if (sel == ITEM_NONE)
100  sel = 0;
101  else
102  sel --;
103  }
104  }
105  else if (_key == KeyCode::ArrowDown)
106  {
107  if (sel == ITEM_NONE)
108  sel = 0;
109  else
110  sel ++;
111 
112  if (sel >= getItemCount())
113  {
114  // старое значение
115  sel = mIndexSelect;
116  }
117  }
118  else if (_key == KeyCode::Home)
119  {
120  sel = 0;
121  }
122  else if (_key == KeyCode::End)
123  {
124  sel = getItemCount() - 1;
125  }
126  else if (_key == KeyCode::PageUp)
127  {
128  if (sel != 0)
129  {
130  if (sel == ITEM_NONE)
131  {
132  sel = 0;
133  }
134  else
135  {
136  size_t page = _getClientWidget()->getHeight() / mHeightLine;
137  if (sel <= page)
138  sel = 0;
139  else
140  sel -= page;
141  }
142  }
143  }
144  else if (_key == KeyCode::PageDown)
145  {
146  if (sel != (getItemCount() - 1))
147  {
148  if (sel == ITEM_NONE)
149  {
150  sel = 0;
151  }
152  else
153  {
154  sel += _getClientWidget()->getHeight() / mHeightLine;
155  if (sel >= getItemCount())
156  sel = getItemCount() - 1;
157  }
158  }
159  }
160  else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
161  {
162  if (sel != ITEM_NONE)
163  {
164  //FIXME нас могут удалить
165  eventListSelectAccept(this, sel);
166 
167  Base::onKeyButtonPressed(_key, _char);
168 
170  // выходим, так как изменили колличество строк
171  return;
172  }
173  }
174 
175  if (sel != mIndexSelect)
176  {
177  _resetContainer(true);
178 
179  if (!isItemVisibleAt(sel))
180  {
181  beginToItemAt(sel);
182  if (mWidgetScroll != nullptr)
183  _sendEventChangeScroll(mWidgetScroll->getScrollPosition());
184  }
185  setIndexSelected(sel);
186 
187  // изменилась позиция
188  // FIXME нас могут удалить
189  eventListChangePosition(this, mIndexSelect);
190  }
191 
192  Base::onKeyButtonPressed(_key, _char);
194  }
195 
196  void ListBox::notifyMouseWheel(Widget* _sender, int _rel)
197  {
198  if (mRangeIndex <= 0)
199  return;
200 
201  if (mWidgetScroll == nullptr)
202  return;
203 
204  int offset = (int)mWidgetScroll->getScrollPosition();
205  if (_rel < 0)
206  offset += mHeightLine;
207  else
208  offset -= mHeightLine;
209 
210  if (offset >= mRangeIndex)
211  offset = mRangeIndex;
212  else if (offset < 0)
213  offset = 0;
214 
215  if ((int)mWidgetScroll->getScrollPosition() == offset)
216  return;
217 
218  mWidgetScroll->setScrollPosition(offset);
219  _setScrollView(offset);
220  _sendEventChangeScroll(offset);
221 
222  _resetContainer(true);
223  }
224 
225  void ListBox::notifyScrollChangePosition(ScrollBar* _sender, size_t _position)
226  {
227  _setScrollView(_position);
228  _sendEventChangeScroll(_position);
229  }
230 
231  void ListBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
232  {
233  if (MouseButton::Left == _id && !mActivateOnClick)
234  _activateItem(_sender);
235 
236  eventNotifyItem(this, IBNotifyItemData(getIndexByWidget(_sender), IBNotifyItemData::MousePressed, _left, _top, _id));
237  }
238 
240  {
241  if (mActivateOnClick)
242  _activateItem(_sender);
243  }
244 
246  {
247  if (mIndexSelect != ITEM_NONE)
248  eventListSelectAccept(this, mIndexSelect);
249  }
250 
251  void ListBox::setPosition(const IntPoint& _point)
252  {
253  Base::setPosition(_point);
254  }
255 
256  void ListBox::setSize(const IntSize& _size)
257  {
258  Base::setSize(_size);
259 
260  updateScroll();
261  updateLine();
262  }
263 
264  void ListBox::setCoord(const IntCoord& _coord)
265  {
266  Base::setCoord(_coord);
267 
268  updateScroll();
269  updateLine();
270  }
271 
273  {
274  mRangeIndex = (mHeightLine * (int)mItemsInfo.size()) - _getClientWidget()->getHeight();
275 
276  if (mWidgetScroll == nullptr)
277  return;
278 
279  if ((!mNeedVisibleScroll) || (mRangeIndex < 1) || (mWidgetScroll->getLeft() <= _getClientWidget()->getLeft()))
280  {
281  if (mWidgetScroll->getVisible())
282  {
283  mWidgetScroll->setVisible(false);
284  // увеличиваем клиентскую зону на ширину скрола
285  if (getClientWidget() != nullptr)
287  }
288  }
289  else if (!mWidgetScroll->getVisible())
290  {
291  if (getClientWidget() != nullptr)
293  mWidgetScroll->setVisible(true);
294  }
295 
296  mWidgetScroll->setScrollRange(mRangeIndex + 1);
297  mWidgetScroll->setScrollViewPage(_getClientWidget()->getHeight());
298  if (!mItemsInfo.empty())
299  mWidgetScroll->setTrackSize(mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size());
300  }
301 
302  void ListBox::updateLine(bool _reset)
303  {
304  // сбрасываем
305  if (_reset)
306  {
307  mOldSize.clear();
308  mLastRedrawLine = 0;
309  _resetContainer(false);
310  }
311 
312  // позиция скролла
313  int position = mTopIndex * mHeightLine + mOffsetTop;
314 
315  // если высота увеличивалась то добавляем виджеты
316  if (mOldSize.height < mCoord.height)
317  {
318  int height = (int)mWidgetLines.size() * mHeightLine - mOffsetTop;
319 
320  // до тех пор, пока не достигнем максимального колличества, и всегда на одну больше
321  while ( (height <= (_getClientWidget()->getHeight() + mHeightLine)) && (mWidgetLines.size() < mItemsInfo.size()) )
322  {
323  // создаем линию
324  Widget* widget = _getClientWidget()->createWidgetT("Button", mSkinLine, 0, height, _getClientWidget()->getWidth(), mHeightLine, Align::Top | Align::HStretch);
325  Button* line = widget->castType<Button>();
326  // подписываемся на всякие там события
336  line->_setContainer(this);
337  // присваиваем порядковый номер, для простоты просчета
338  line->_setInternalData((size_t)mWidgetLines.size());
339  // и сохраняем
340  mWidgetLines.push_back(line);
341  height += mHeightLine;
342  }
343 
344  // проверяем на возможность не менять положение списка
345  if (position >= mRangeIndex)
346  {
347  // размер всех помещается в клиент
348  if (mRangeIndex <= 0)
349  {
350  // обнуляем, если надо
351  if (position || mOffsetTop || mTopIndex)
352  {
353  position = 0;
354  mTopIndex = 0;
355  mOffsetTop = 0;
356  mLastRedrawLine = 0; // чтобы все перерисовалось
357 
358  // выравниваем
359  int offset = 0;
360  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
361  {
362  mWidgetLines[pos]->setPosition(0, offset);
363  offset += mHeightLine;
364  }
365  }
366  }
367  else
368  {
369  // прижимаем список к нижней границе
370  int count = _getClientWidget()->getHeight() / mHeightLine;
371  mOffsetTop = mHeightLine - (_getClientWidget()->getHeight() % mHeightLine);
372 
373  if (mOffsetTop == mHeightLine)
374  {
375  mOffsetTop = 0;
376  count --;
377  }
378 
379  int top = (int)mItemsInfo.size() - count - 1;
380 
381  // выравниваем
382  int offset = 0 - mOffsetTop;
383  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
384  {
385  mWidgetLines[pos]->setPosition(0, offset);
386  offset += mHeightLine;
387  }
388 
389  // высчитываем положение, должно быть максимальным
390  position = top * mHeightLine + mOffsetTop;
391 
392  // если индех изменился, то перерисовываем линии
393  if (top != mTopIndex)
394  {
395  mTopIndex = top;
397  }
398  }
399  }
400 
401  // увеличился размер, но прокрутки вниз небыло, обновляем линии снизу
402  _redrawItemRange(mLastRedrawLine);
403 
404  } // if (old_cy < mCoord.height)
405 
406  // просчитываем положение скролла
407  if (mWidgetScroll != nullptr)
408  mWidgetScroll->setScrollPosition(position);
409 
410  mOldSize.width = mCoord.width;
411  mOldSize.height = mCoord.height;
412 
413 #if MYGUI_DEBUG_MODE == 1
414  _checkMapping("ListBox::updateLine");
415 #endif
416  }
417 
418  void ListBox::_redrawItemRange(size_t _start)
419  {
420  // перерисовываем линии, только те, что видны
421  size_t pos = _start;
422  for (; pos < mWidgetLines.size(); pos++)
423  {
424  // индекс в нашем массиве
425  size_t index = pos + (size_t)mTopIndex;
426 
427  // не будем заходить слишком далеко
428  if (index >= mItemsInfo.size())
429  {
430  // запоминаем последнюю перерисованную линию
431  mLastRedrawLine = pos;
432  break;
433  }
434  if (mWidgetLines[pos]->getTop() > _getClientWidget()->getHeight())
435  {
436  // запоминаем последнюю перерисованную линию
437  mLastRedrawLine = pos;
438  break;
439  }
440 
441  // если был скрыт, то покажем
442  mWidgetLines[pos]->setVisible(true);
443  // обновляем текст
444  mWidgetLines[pos]->setCaption(mItemsInfo[index].first);
445 
446  // если нужно выделить ,то выделим
447  static_cast<Button*>(mWidgetLines[pos])->setStateSelected(index == mIndexSelect);
448  }
449 
450  // если цикл весь прошли, то ставим максимальную линию
451  if (pos >= mWidgetLines.size())
452  {
453  mLastRedrawLine = pos;
454  }
455  else
456  {
457  //Widget* focus = InputManager::getInstance().getMouseFocusWidget();
458  for (; pos < mWidgetLines.size(); pos++)
459  {
460  static_cast<Button*>(mWidgetLines[pos])->setStateSelected(false);
461  static_cast<Button*>(mWidgetLines[pos])->setVisible(false);
462  //if (focus == mWidgetLines[pos]) InputManager::getInstance()._unlinkWidget(focus);
463  }
464  }
465 
466 #if MYGUI_DEBUG_MODE == 1
467  _checkMapping("ListBox::_redrawItemRange");
468 #endif
469  }
470 
471  // перерисовывает индекс
472  void ListBox::_redrawItem(size_t _index)
473  {
474  // невидно
475  if (_index < (size_t)mTopIndex)
476  return;
477  _index -= (size_t)mTopIndex;
478  // тоже невидно
479  if (_index >= mLastRedrawLine)
480  return;
481 
482  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::_redrawItem");
483  // перерисовываем
484  mWidgetLines[_index]->setCaption(mItemsInfo[_index + mTopIndex].first);
485 
486 #if MYGUI_DEBUG_MODE == 1
487  _checkMapping("ListBox::_redrawItem");
488 #endif
489  }
490 
491  void ListBox::insertItemAt(size_t _index, const UString& _name, Any _data)
492  {
493  MYGUI_ASSERT_RANGE_INSERT(_index, mItemsInfo.size(), "ListBox::insertItemAt");
494  if (_index == ITEM_NONE)
495  _index = mItemsInfo.size();
496 
497  // вставляем физически
498  mItemsInfo.insert(mItemsInfo.begin() + _index, PairItem(_name, _data));
499 
500  // если надо, то меняем выделенный элемент
501  if ((mIndexSelect != ITEM_NONE) && (_index <= mIndexSelect))
502  mIndexSelect++;
503 
504  // строка, до первого видимого элемента
505  if ((_index <= (size_t)mTopIndex) && (mRangeIndex > 0))
506  {
507  mTopIndex ++;
508  // просчитываем положение скролла
509  if (mWidgetScroll != nullptr)
510  {
511  mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() + mHeightLine);
512  if (!mItemsInfo.empty())
513  mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() );
514  mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
515  }
516  mRangeIndex += mHeightLine;
517  }
518  else
519  {
520  // высчитывам положение строки
521  int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
522 
523  // строка, после последнего видимого элемента, плюс одна строка (потому что для прокрутки нужно на одну строчку больше)
524  if (_getClientWidget()->getHeight() < (offset - mHeightLine))
525  {
526  // просчитываем положение скролла
527  if (mWidgetScroll != nullptr)
528  {
529  mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() + mHeightLine);
530  if (!mItemsInfo.empty())
531  mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() );
532  mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
533  }
534  mRangeIndex += mHeightLine;
535 
536  // строка в видимой области
537  }
538  else
539  {
540  // обновляем все
541  updateScroll();
542  updateLine(true);
543 
544  // позже сюда еще оптимизацию по колличеству перерисовок
545  }
546  }
547 
548 #if MYGUI_DEBUG_MODE == 1
549  _checkMapping("ListBox::insertItemAt");
550 #endif
551  }
552 
553  void ListBox::removeItemAt(size_t _index)
554  {
555  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::removeItemAt");
556 
557  // удяляем физически строку
558  mItemsInfo.erase(mItemsInfo.begin() + _index);
559 
560  // если надо, то меняем выделенный элемент
561  if (mItemsInfo.empty()) mIndexSelect = ITEM_NONE;
562  else if (mIndexSelect != ITEM_NONE)
563  {
564  if (_index < mIndexSelect)
565  mIndexSelect--;
566  else if ((_index == mIndexSelect) && (mIndexSelect == (mItemsInfo.size())))
567  mIndexSelect--;
568  }
569 
570  // если виджетов стало больше , то скрываем крайний
571  if (mWidgetLines.size() > mItemsInfo.size())
572  {
573  mWidgetLines[mItemsInfo.size()]->setVisible(false);
574  }
575 
576  // строка, до первого видимого элемента
577  if (_index < (size_t)mTopIndex)
578  {
579  mTopIndex --;
580  // просчитываем положение скролла
581  if (mWidgetScroll != nullptr)
582  {
583  mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() - mHeightLine);
584  if (!mItemsInfo.empty())
585  mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() );
586  mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
587  }
588  mRangeIndex -= mHeightLine;
589  }
590  else
591  {
592  // высчитывам положение удаляемой строки
593  int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
594 
595  // строка, после последнего видимого элемента
596  if (_getClientWidget()->getHeight() < offset)
597  {
598  // просчитываем положение скролла
599  if (mWidgetScroll != nullptr)
600  {
601  mWidgetScroll->setScrollRange(mWidgetScroll->getScrollRange() - mHeightLine);
602  if (!mItemsInfo.empty())
603  mWidgetScroll->setTrackSize( mWidgetScroll->getLineSize() * _getClientWidget()->getHeight() / mHeightLine / (int)mItemsInfo.size() );
604  mWidgetScroll->setScrollPosition(mTopIndex * mHeightLine + mOffsetTop);
605  }
606  mRangeIndex -= mHeightLine;
607 
608  // строка в видимой области
609  }
610  else
611  {
612  // обновляем все
613  updateScroll();
614  updateLine(true);
615 
616  // позже сюда еще оптимизацию по колличеству перерисовок
617  }
618  }
619 
620 #if MYGUI_DEBUG_MODE == 1
621  _checkMapping("ListBox::removeItemAt");
622 #endif
623  }
624 
625  void ListBox::setIndexSelected(size_t _index)
626  {
627  MYGUI_ASSERT_RANGE_AND_NONE(_index, mItemsInfo.size(), "ListBox::setIndexSelected");
628  if (mIndexSelect != _index)
629  {
630  _selectIndex(mIndexSelect, false);
631  _selectIndex(_index, true);
632  mIndexSelect = _index;
633  }
634  }
635 
636  void ListBox::_selectIndex(size_t _index, bool _select)
637  {
638  if (_index == ITEM_NONE)
639  return;
640  // не видно строки
641  if (_index < (size_t)mTopIndex)
642  return;
643  // высчитывам положение строки
644  int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
645  // строка, после последнего видимого элемента
646  if (_getClientWidget()->getHeight() < offset)
647  return;
648 
649  size_t index = _index - mTopIndex;
650  if (index < mWidgetLines.size())
651  static_cast<Button*>(mWidgetLines[index])->setStateSelected(_select);
652 
653 #if MYGUI_DEBUG_MODE == 1
654  _checkMapping("ListBox::_selectIndex");
655 #endif
656  }
657 
658  void ListBox::beginToItemAt(size_t _index)
659  {
660  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::beginToItemAt");
661  if (mRangeIndex <= 0)
662  return;
663 
664  int offset = (int)_index * mHeightLine;
665  if (offset >= mRangeIndex) offset = mRangeIndex;
666 
667  if (mWidgetScroll != nullptr)
668  {
669  if ((int)mWidgetScroll->getScrollPosition() == offset)
670  return;
671  mWidgetScroll->setScrollPosition(offset);
672  }
673  notifyScrollChangePosition(nullptr, offset);
674 
675 #if MYGUI_DEBUG_MODE == 1
676  _checkMapping("ListBox::beginToItemAt");
677 #endif
678  }
679 
680  // видим ли мы элемент, полностью или нет
681  bool ListBox::isItemVisibleAt(size_t _index, bool _fill)
682  {
683  // если элемента нет, то мы его не видим (в том числе когда их вообще нет)
684  if (_index >= mItemsInfo.size())
685  return false;
686  // если скрола нет, то мы палюбак видим
687  if (mRangeIndex <= 0)
688  return true;
689 
690  // строка, до первого видимого элемента
691  if (_index < (size_t)mTopIndex)
692  return false;
693 
694  // строка это верхний выделенный
695  if (_index == (size_t)mTopIndex)
696  {
697  if ((mOffsetTop != 0) && (_fill))
698  return false; // нам нужна полностью видимость
699  return true;
700  }
701 
702  // высчитывам положение строки
703  int offset = ((int)_index - mTopIndex) * mHeightLine - mOffsetTop;
704 
705  // строка, после последнего видимого элемента
706  if (_getClientWidget()->getHeight() < offset)
707  return false;
708 
709  // если мы внизу и нам нужен целый
710  if (_getClientWidget()->getHeight() < (offset + mHeightLine) && _fill)
711  return false;
712 
713  return true;
714  }
715 
717  {
718  mTopIndex = 0;
719  mIndexSelect = ITEM_NONE;
720  mOffsetTop = 0;
721 
722  mItemsInfo.clear();
723 
724  int offset = 0;
725  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
726  {
727  mWidgetLines[pos]->setVisible(false);
728  mWidgetLines[pos]->setPosition(0, offset);
729  offset += mHeightLine;
730  }
731 
732  // обновляем все
733  updateScroll();
734  updateLine(true);
735 
736 #if MYGUI_DEBUG_MODE == 1
737  _checkMapping("ListBox::removeAllItems");
738 #endif
739  }
740 
741  void ListBox::setItemNameAt(size_t _index, const UString& _name)
742  {
743  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::setItemNameAt");
744  mItemsInfo[_index].first = _name;
745  _redrawItem(_index);
746  }
747 
748  void ListBox::setItemDataAt(size_t _index, Any _data)
749  {
750  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::setItemDataAt");
751  mItemsInfo[_index].second = _data;
752  _redrawItem(_index);
753  }
754 
755  const UString& ListBox::getItemNameAt(size_t _index) const
756  {
757  MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "ListBox::getItemNameAt");
758  return mItemsInfo[_index].first;
759  }
760 
762  {
763 
764 #if MYGUI_DEBUG_MODE == 1
765  MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>(), mWidgetLines.size(), "ListBox::notifyMouseSetFocus");
766 #endif
767 
768  mLineActive = *_sender->_getInternalData<size_t>();
769  eventListMouseItemFocus(this, mLineActive);
770  }
771 
773  {
774  if ((nullptr == _new) || (_new->getParent() != _getClientWidget()))
775  {
776  mLineActive = ITEM_NONE;
778  }
779  }
780 
781  void ListBox::_setItemFocus(size_t _index, bool _focus)
782  {
783  MYGUI_ASSERT_RANGE(_index, mWidgetLines.size(), "ListBox::_setItemFocus");
784  static_cast<Button*>(mWidgetLines[_index])->_setMouseFocus(_focus);
785  }
786 
787  void ListBox::setScrollVisible(bool _visible)
788  {
789  if (mNeedVisibleScroll == _visible)
790  return;
791  mNeedVisibleScroll = _visible;
792  updateScroll();
793  }
794 
795  void ListBox::setScrollPosition(size_t _position)
796  {
797  if (mWidgetScroll != nullptr)
798  {
799  if (mWidgetScroll->getScrollRange() > _position)
800  {
801  mWidgetScroll->setScrollPosition(_position);
802  _setScrollView(_position);
803  }
804  }
805  }
806 
807  void ListBox::_setScrollView(size_t _position)
808  {
809  mOffsetTop = ((int)_position % mHeightLine);
810 
811  // смещение с отрицательной стороны
812  int offset = 0 - mOffsetTop;
813 
814  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
815  {
816  mWidgetLines[pos]->setPosition(IntPoint(0, offset));
817  offset += mHeightLine;
818  }
819 
820  // если индех изменился, то перерисовываем линии
821  int top = ((int)_position / mHeightLine);
822  if (top != mTopIndex)
823  {
824  mTopIndex = top;
826  }
827 
828  // прорисовываем все нижние строки, если они появились
829  _redrawItemRange(mLastRedrawLine);
830  }
831 
832  void ListBox::_sendEventChangeScroll(size_t _position)
833  {
834  eventListChangeScroll(this, _position);
835  if (ITEM_NONE != mLineActive)
836  eventListMouseItemFocus(this, mLineActive);
837  }
838 
839  void ListBox::swapItemsAt(size_t _index1, size_t _index2)
840  {
841  MYGUI_ASSERT_RANGE(_index1, mItemsInfo.size(), "ListBox::swapItemsAt");
842  MYGUI_ASSERT_RANGE(_index2, mItemsInfo.size(), "ListBox::swapItemsAt");
843 
844  if (_index1 == _index2)
845  return;
846 
847  std::swap(mItemsInfo[_index1], mItemsInfo[_index2]);
848 
849  _redrawItem(_index1);
850  _redrawItem(_index2);
851  }
852 
853  void ListBox::_checkMapping(const std::string& _owner)
854  {
855  size_t count_pressed = 0;
856  size_t count_show = 0;
857 
858  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
859  {
860  MYGUI_ASSERT(pos == *mWidgetLines[pos]->_getInternalData<size_t>(), _owner);
861  if (static_cast<Button*>(mWidgetLines[pos])->getStateSelected())
862  count_pressed ++;
863  if (static_cast<Button*>(mWidgetLines[pos])->getVisible())
864  count_show ++;
865  }
866  //MYGUI_ASSERT(count_pressed < 2, _owner);
867  //MYGUI_ASSERT((count_show + mOffsetTop) <= mItemsInfo.size(), _owner);
868  }
869 
871  {
872  // максимальная высота всех строк
873  int max_height = mItemsInfo.size() * mHeightLine;
874  // видимая высота
875  int visible_height = _getClientWidget()->getHeight();
876 
877  // все строки помещаются
878  if (visible_height >= max_height)
879  {
880  MYGUI_ASSERT(mTopIndex == 0, "mTopIndex == 0");
881  MYGUI_ASSERT(mOffsetTop == 0, "mOffsetTop == 0");
882  int height = 0;
883  for (size_t pos = 0; pos < mWidgetLines.size(); pos++)
884  {
885  if (pos >= mItemsInfo.size())
886  break;
887  MYGUI_ASSERT(mWidgetLines[pos]->getTop() == height, "mWidgetLines[pos]->getTop() == height");
888  height += mWidgetLines[pos]->getHeight();
889  }
890  }
891  }
892 
893  size_t ListBox::findItemIndexWith(const UString& _name)
894  {
895  for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
896  {
897  if (mItemsInfo[pos].first == _name)
898  return pos;
899  }
900  return ITEM_NONE;
901  }
902 
904  {
905  return (int)((mCoord.height - _getClientWidget()->getHeight()) + (mItemsInfo.size() * mHeightLine));
906  }
907 
908  size_t ListBox::getItemCount() const
909  {
910  return mItemsInfo.size();
911  }
912 
913  void ListBox::addItem(const UString& _name, Any _data)
914  {
915  insertItemAt(ITEM_NONE, _name, _data);
916  }
917 
919  {
920  return mIndexSelect;
921  }
922 
924  {
926  }
927 
928  void ListBox::clearItemDataAt(size_t _index)
929  {
930  setItemDataAt(_index, Any::Null);
931  }
932 
934  {
935  if (getItemCount())
936  beginToItemAt(0);
937  }
938 
940  {
941  if (getItemCount())
943  }
944 
946  {
947  if (getIndexSelected() != ITEM_NONE)
949  }
950 
952  {
953  return isItemVisibleAt(mIndexSelect, _fill);
954  }
955 
956  size_t ListBox::_getItemIndex(Widget* _item) const
957  {
958  for (const auto& line : mWidgetLines)
959  {
960  if (line == _item)
961  return *line->_getInternalData<size_t>() + mTopIndex;
962  }
963  return ITEM_NONE;
964  }
965 
966  void ListBox::_resetContainer(bool _update)
967  {
968  // обязательно у базового
969  Base::_resetContainer(_update);
970 
971  if (!_update)
972  {
974  for (const auto& line : mWidgetLines)
975  instance.unlinkFromUnlinkers(line);
976  }
977  }
978 
979  void ListBox::setPropertyOverride(const std::string& _key, const std::string& _value)
980  {
981  // не коментировать
982  if (_key == "AddItem")
983  addItem(_value);
984  else if (_key == "ActivateOnClick")
985  mActivateOnClick = utility::parseBool(_value);
986  else
987  {
988  Base::setPropertyOverride(_key, _value);
989  return;
990  }
991 
992  eventChangeProperty(this, _key, _value);
993  }
994 
996  {
997  // если выделен клиент, то сбрасываем
998  if (_sender == _getClientWidget())
999  {
1000  if (mIndexSelect != ITEM_NONE)
1001  {
1002  _selectIndex(mIndexSelect, false);
1003  mIndexSelect = ITEM_NONE;
1004  eventListChangePosition(this, mIndexSelect);
1005  }
1006  eventListMouseItemActivate(this, mIndexSelect);
1007 
1008  // если не клиент, то просчитывам
1009  }
1010  // ячейка может быть скрыта
1011  else if (_sender->getVisible())
1012  {
1013 
1014 #if MYGUI_DEBUG_MODE == 1
1015  _checkMapping("ListBox::notifyMousePressed");
1016  MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>(), mWidgetLines.size(), "ListBox::notifyMousePressed");
1017  MYGUI_ASSERT_RANGE(*_sender->_getInternalData<size_t>() + mTopIndex, mItemsInfo.size(), "ListBox::notifyMousePressed");
1018 #endif
1019 
1020  size_t index = *_sender->_getInternalData<size_t>() + mTopIndex;
1021 
1022  if (mIndexSelect != index)
1023  {
1024  _selectIndex(mIndexSelect, false);
1025  _selectIndex(index, true);
1026  mIndexSelect = index;
1027  eventListChangePosition(this, mIndexSelect);
1028  }
1029  eventListMouseItemActivate(this, mIndexSelect);
1030  }
1031 
1032  _resetContainer(true);
1033  }
1034 
1035  size_t ListBox::_getItemCount() const
1036  {
1037  return getItemCount();
1038  }
1039 
1041  {
1042  addItem(_name);
1043  }
1044 
1045  void ListBox::_removeItemAt(size_t _index)
1046  {
1047  removeItemAt(_index);
1048  }
1049 
1050  void ListBox::_setItemNameAt(size_t _index, const UString& _name)
1051  {
1052  setItemNameAt(_index, _name);
1053  }
1054 
1055  const UString& ListBox::_getItemNameAt(size_t _index) const
1056  {
1057  return getItemNameAt(_index);
1058  }
1059 
1060  size_t ListBox::getIndexByWidget(Widget* _widget) const
1061  {
1062  if (_widget == getClientWidget())
1063  return ITEM_NONE;
1064  return *_widget->_getInternalData<size_t>() + mTopIndex;
1065  }
1066 
1068  {
1069  eventNotifyItem(this, IBNotifyItemData(getIndexByWidget(_sender), IBNotifyItemData::KeyPressed, _key, _char));
1070  }
1071 
1073  {
1074  eventNotifyItem(this, IBNotifyItemData(getIndexByWidget(_sender), IBNotifyItemData::KeyReleased, _key));
1075  }
1076 
1077  void ListBox::notifyMouseButtonReleased(Widget* _sender, int _left, int _top, MouseButton _id)
1078  {
1079  eventNotifyItem(this, IBNotifyItemData(getIndexByWidget(_sender), IBNotifyItemData::MouseReleased, _left, _top, _id));
1080  }
1081 
1083  {
1084  Base::onKeyButtonReleased(_key);
1085 
1087  }
1088 
1089  void ListBox::setActivateOnClick(bool activateOnClick)
1090  {
1091  mActivateOnClick = activateOnClick;
1092  }
1093 
1095  {
1096  if (_index == MyGUI::ITEM_NONE)
1097  return nullptr;
1098 
1099  // индекс в нашем массиве
1100  size_t index = _index - (size_t)mTopIndex;
1101 
1102  if (index < mWidgetLines.size())
1103  return mWidgetLines[index];
1104  return nullptr;
1105  }
1106 
1107 } // namespace MyGUI
#define MYGUI_ASSERT(exp, dest)
#define MYGUI_ASSERT_RANGE_INSERT(index, size, owner)
#define MYGUI_ASSERT_RANGE(index, size, owner)
#define MYGUI_ASSERT_RANGE_AND_NONE(index, size, owner)
static AnyEmpty Null
Definition: MyGUI_Any.h:59
widget description should be here.
Definition: MyGUI_Button.h:22
void setStateSelected(bool _value)
Set button selected state.
Type * castType(bool _throw=true)
Definition: MyGUI_IObject.h:18
void _setItemNameAt(size_t _index, const UString &_name) override
void addItem(const UString &_name, Any _data=Any::Null)
Add an item to the end of a array.
void notifyMouseWheel(Widget *_sender, int _rel)
void setCoord(const IntCoord &_value) override
void _removeItemAt(size_t _index) override
void updateLine(bool _reset=false)
EventHandle_ListBoxPtrCIBNotifyCellDataRef eventNotifyItem
void beginToItemAt(size_t _index)
Move all elements so specified becomes visible.
void _redrawItem(size_t _index)
size_t _getItemIndex(Widget *_item) const override
void _setScrollView(size_t _position)
void notifyKeyButtonReleased(Widget *_sender, KeyCode _key)
void notifyMousePressed(Widget *_sender, int _left, int _top, MouseButton _id)
void _sendEventChangeScroll(size_t _position)
void setScrollPosition(size_t _position)
Set scroll position.
void notifyMouseButtonReleased(Widget *_sender, int _left, int _top, MouseButton _id)
bool isItemSelectedVisible(bool _fill=true)
Same as ListBox::isItemVisibleAt for selected item.
void _resetContainer(bool _update) override
const UString & _getItemNameAt(size_t _index) const override
bool isItemVisibleAt(size_t _index, bool _fill=true)
const UString & getItemNameAt(size_t _index) const
Get item name from specified position.
void notifyMouseClick(Widget *_sender)
void setActivateOnClick(bool activateOnClick)
void setPropertyOverride(const std::string &_key, const std::string &_value) override
void clearIndexSelected()
void _addItem(const MyGUI::UString &_name) override
void setScrollVisible(bool _visible)
Set scroll visible when it needed.
void _activateItem(Widget *_sender)
void setPosition(const IntPoint &_value) override
void _redrawItemRange(size_t _start=0)
void notifyMouseLostFocus(Widget *_sender, Widget *_new)
void shutdownOverride() override
void setSize(const IntSize &_value) override
size_t getItemCount() const
Get number of items.
void notifyScrollChangePosition(ScrollBar *_sender, size_t _rel)
void initialiseOverride() override
void notifyMouseSetFocus(Widget *_sender, Widget *_old)
void swapItemsAt(size_t _index1, size_t _index2)
Swap items at a specified positions.
int getOptimalHeight() const
Return optimal height to fit all items in ListBox.
void onKeyButtonReleased(KeyCode _key) override
void insertItemAt(size_t _index, const UString &_name, Any _data=Any::Null)
Insert an item into a array at a specified position.
void removeAllItems()
Remove all items.
EventPair< EventHandle_WidgetSizeT, EventHandle_ListPtrSizeT > eventListChangePosition
void onMouseWheel(int _rel) override
void clearItemDataAt(size_t _index)
Clear an item data at a specified position.
size_t getIndexSelected() const
void _selectIndex(size_t _index, bool _select)
size_t _getItemCount() const override
EventPair< EventHandle_WidgetSizeT, EventHandle_ListPtrSizeT > eventListMouseItemFocus
size_t findItemIndexWith(const UString &_name)
Search item, returns the position of the first occurrence in array or ITEM_NONE if item not found.
void beginToItemFirst()
Move all elements so first becomes visible.
EventPair< EventHandle_WidgetSizeT, EventHandle_ListPtrSizeT > eventListChangeScroll
void notifyKeyButtonPressed(Widget *_sender, KeyCode _key, Char _char)
void onKeyButtonPressed(KeyCode _key, Char _char) override
void setItemDataAt(size_t _index, Any _data)
Replace an item data at a specified position.
void notifyMouseDoubleClick(Widget *_sender)
Widget * getWidgetByIndex(size_t _index)
EventPair< EventHandle_WidgetSizeT, EventHandle_ListPtrSizeT > eventListSelectAccept
void beginToItemSelected()
Move all elements so selected becomes visible.
void removeItemAt(size_t _index)
Remove item at a specified position.
void setItemNameAt(size_t _index, const UString &_name)
Replace an item name at a specified position.
void setIndexSelected(size_t _index)
void _setItemFocus(size_t _position, bool _focus)
void beginToItemLast()
Move all elements so last becomes visible.
EventPair< EventHandle_WidgetSizeT, EventHandle_ListPtrSizeT > eventListMouseItemActivate
widget description should be here.
EventHandle_ScrollBarPtrSizeT eventScrollChangePosition
void setScrollRange(size_t _value)
int getLineSize() const
void setTrackSize(int _value)
size_t getScrollPosition() const
void setScrollPosition(size_t _value)
size_t getScrollRange() const
void setScrollViewPage(size_t _value)
void setScrollPage(size_t _value)
A UTF-16 string with implicit conversion to/from std::string and std::wstring.
bool isUserString(const std::string &_key) const
ValueType * _getInternalData(bool _throw=true) const
void _setInternalData(Any _data)
const std::string & getUserString(const std::string &_key) const
widget description should be here.
Definition: MyGUI_Widget.h:37
Widget * getParent() const
Widget * createWidgetT(const std::string &_type, const std::string &_skin, const IntCoord &_coord, Align _align, const std::string &_name="")
EventHandle_WidgetStringString eventChangeProperty
Definition: MyGUI_Widget.h:267
void assignWidget(T *&_widget, const std::string &_name)
Definition: MyGUI_Widget.h:335
virtual void setVisible(bool _value)
bool getVisible() const
void setSize(const IntSize &_value) override
Widget * getClientWidget()
void _setContainer(Widget *_value)
Widget * _getClientWidget()
If there is client widget return it, otherwise return this.
EventHandle_WidgetVoid eventMouseButtonDoubleClick
EventHandle_WidgetVoid eventMouseButtonClick
EventHandle_WidgetIntIntButton eventMouseButtonReleased
void setNeedKeyFocus(bool _value)
EventHandle_WidgetIntIntButton eventMouseButtonPressed
EventHandle_WidgetWidget eventMouseSetFocus
EventHandle_WidgetKeyCodeChar eventKeyButtonPressed
EventHandle_WidgetWidget eventMouseLostFocus
EventHandle_WidgetInt eventMouseWheel
EventHandle_WidgetKeyCode eventKeyButtonReleased
static WidgetManager & getInstance()
void unlinkFromUnlinkers(Widget *_widget)
int parseInt(const std::string &_value)
bool parseBool(const std::string &_value)
delegates::DelegateFunction< Args... > * newDelegate(void(*_func)(Args... args))
const size_t ITEM_NONE
Definition: MyGUI_Macros.h:17
types::TPoint< int > IntPoint
Definition: MyGUI_Types.h:26
unsigned int Char
Definition: MyGUI_Types.h:49