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