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
15namespace 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
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)
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);
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
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
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 {
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
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 _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 setPosition(const IntPoint &_value) override
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 setSize(const IntSize &_value) override
void _redrawItemRange(size_t _start=0)
void notifyMouseLostFocus(Widget *_sender, Widget *_new)
void shutdownOverride() 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.
void setCoord(const IntCoord &_value) override
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
void _setInternalData(Any _data)
const std::string & getUserString(const std::string &_key) const
ValueType * _getInternalData(bool _throw=true) 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)
const size_t ITEM_NONE
Definition: MyGUI_Macros.h:17
delegates::DelegateFunction< Args... > * newDelegate(void(*_func)(Args... args))
types::TPoint< int > IntPoint
Definition: MyGUI_Types.h:26
unsigned int Char
Definition: MyGUI_Types.h:49