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