MyGUI 3.4.3
MyGUI_MultiListBox.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"
10#include "MyGUI_ResourceSkin.h"
11#include "MyGUI_Button.h"
12#include "MyGUI_ImageBox.h"
13#include "MyGUI_ListBox.h"
14#include "MyGUI_Gui.h"
15#include "MyGUI_WidgetManager.h"
16
17namespace MyGUI
18{
19
21 {
23
24 if (isUserString("SkinButton"))
25 mSkinButton = getUserString("SkinButton");
26
27 if (isUserString("SkinList"))
28 mSkinList = getUserString("SkinList");
29
30 if (isUserString("SkinSeparator"))
31 mSkinSeparator = getUserString("SkinSeparator");
32
33 if (isUserString("WidthSeparator"))
34 mWidthSeparator = utility::parseValue<int>(getUserString("WidthSeparator"));
35
36 // OBSOLETE
37 if (isUserString("HeightButton"))
38 mHeightButton = utility::parseValue<int>(getUserString("HeightButton"));
39 if (mHeightButton < 0)
40 mHeightButton = 0;
41
43 assignWidget(mHeaderPlace, "HeaderPlace");
44
46 assignWidget(mWidgetEmpty, "Empty");
47
48 if (mWidgetEmpty == nullptr)
49 {
50 std::string_view skinButtonEmpty;
51 if (isUserString("SkinButtonEmpty"))
52 skinButtonEmpty = getUserString("SkinButtonEmpty");
53
54 if (!skinButtonEmpty.empty())
55 mWidgetEmpty = _getClientWidget()->createWidget<Widget>(
56 skinButtonEmpty,
57 IntCoord(0, 0, _getClientWidget()->getWidth(), getButtonHeight()),
59 }
60
61 if (getUpdateByResize())
62 updateColumns();
63 }
64
69
70 void MultiListBox::setColumnNameAt(size_t _column, const UString& _name)
71 {
72 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::setColumnNameAt");
73 mVectorColumnInfo[_column].name = _name;
74 // обновляем кэпшен сначала
75 redrawButtons();
76 updateColumns();
77 }
78
79 void MultiListBox::setColumnWidthAt(size_t _column, int _width)
80 {
81 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::setColumnWidthAt");
82 mVectorColumnInfo[_column].width = _width;
83 updateColumns();
84 }
85
86 const UString& MultiListBox::getColumnNameAt(size_t _column) const
87 {
88 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::getColumnNameAt");
89 return mVectorColumnInfo[_column].name;
90 }
91
92 int MultiListBox::getColumnWidthAt(size_t _column) const
93 {
94 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::getColumnWidthAt");
95 return mVectorColumnInfo[_column].width;
96 }
97
99 {
100 while (!mVectorColumnInfo.empty())
102 }
103
104 void MultiListBox::sortByColumn(size_t _column, bool _backward)
105 {
106 mSortColumnIndex = _column;
107 if (_backward)
108 {
109 mSortUp = !mSortUp;
110 redrawButtons();
111 // если было недосортированно то сортируем
112 if (mFrameAdvise)
113 sortList();
114
115 flipList();
116 }
117 else
118 {
119 mSortUp = true;
120 redrawButtons();
121 sortList();
122 }
123 }
124
126 {
127 if (mVectorColumnInfo.empty())
128 return 0;
129 return mVectorColumnInfo.front().list->getItemCount();
130 }
131
133 {
135 for (auto& iter : mVectorColumnInfo)
136 {
137 iter.list->removeAllItems();
138 }
139
140 mItemSelected = ITEM_NONE;
141 }
142
143 void MultiListBox::updateBackSelected(size_t _index)
144 {
145 if (_index == ITEM_NONE)
146 {
147 for (auto& iter : mVectorColumnInfo)
148 {
149 iter.list->clearIndexSelected();
150 }
151 }
152 else
153 {
154 for (auto& iter : mVectorColumnInfo)
155 {
156 iter.list->setIndexSelected(_index);
157 }
158 }
159 }
160
162 {
163 if (_index == mItemSelected)
164 return;
165
166 MYGUI_ASSERT(!mVectorColumnInfo.empty(), "MultiListBox::setIndexSelected");
168 _index,
169 mVectorColumnInfo.begin()->list->getItemCount(),
170 "MultiListBox::setIndexSelected");
171
172 mItemSelected = _index;
173 updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
174 }
175
176 void MultiListBox::setSubItemNameAt(size_t _column, size_t _index, const UString& _name)
177 {
178 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::setSubItemAt");
179
180 size_t index = BiIndexBase::convertToBack(_index);
181 getSubItemAt(_column)->setItemNameAt(index, _name);
182
183 // если мы попортили список с активным сортом, надо пересчитывать
184 if (_column == mSortColumnIndex)
185 frameAdvise(true);
186 }
187
188 const UString& MultiListBox::getSubItemNameAt(size_t _column, size_t _index) const
189 {
190 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::getSubItemNameAt");
191
192 size_t index = BiIndexBase::convertToBack(_index);
193 return getSubItemAt(_column)->getItemNameAt(index);
194 }
195
196 size_t MultiListBox::findSubItemWith(size_t _column, const UString& _name)
197 {
198 size_t index = getSubItemAt(_column)->findItemIndexWith(_name);
199 return BiIndexBase::convertToFace(index);
200 }
201
202 int MultiListBox::getButtonHeight() const
203 {
204 if (mHeaderPlace != nullptr)
205 return mHeaderPlace->getHeight();
206 return mHeightButton;
207 }
208
209 void MultiListBox::updateOnlyEmpty()
210 {
211 if (nullptr == mWidgetEmpty)
212 return;
213
214 // кнопка, для заполнения пустоты
215 if (mWidthBar >= _getClientWidget()->getWidth())
216 mWidgetEmpty->setVisible(false);
217 else
218 {
219 mWidgetEmpty->setCoord(mWidthBar, 0, _getClientWidget()->getWidth() - mWidthBar, getButtonHeight());
220 mWidgetEmpty->setVisible(true);
221 }
222 }
223
224 void MultiListBox::notifyListChangePosition(ListBox* _sender, size_t _position)
225 {
226 for (auto& iter : mVectorColumnInfo)
227 {
228 if (_sender != iter.list)
229 iter.list->setIndexSelected(_position);
230 }
231
232 updateBackSelected(_position);
233
234 mItemSelected = BiIndexBase::convertToFace(_position);
235
236 // наш евент
237 eventListChangePosition(this, mItemSelected);
238 }
239
240 void MultiListBox::notifyListSelectAccept(ListBox* _sender, size_t _position)
241 {
242 // наш евент
244 }
245
246 void MultiListBox::notifyListNotifyItem(ListBox* _sender, const MyGUI::IBNotifyItemData& _info)
247 {
248 IBNotifyItemData infoConvertedIndex(_info);
249 infoConvertedIndex.index = BiIndexBase::convertToFace(_info.index);
250 eventNotifyItem(this, infoConvertedIndex);
251 }
252
253 void MultiListBox::notifyListChangeFocus(ListBox* _sender, size_t _position)
254 {
255 for (auto& iter : mVectorColumnInfo)
256 {
257 if (_sender != iter.list)
258 {
259 if (ITEM_NONE != mLastMouseFocusIndex)
260 iter.list->_setItemFocus(mLastMouseFocusIndex, false);
261 if (ITEM_NONE != _position)
262 iter.list->_setItemFocus(_position, true);
263 }
264 }
265 mLastMouseFocusIndex = _position;
266 }
267
268 void MultiListBox::notifyListChangeScrollPosition(ListBox* _sender, size_t _position)
269 {
270 for (auto& iter : mVectorColumnInfo)
271 {
272 if (_sender != iter.list)
273 iter.list->setScrollPosition(_position);
274 }
275 }
276
277 void MultiListBox::notifyButtonClick(MyGUI::Widget* _sender)
278 {
279 size_t index = *_sender->_getInternalData<size_t>();
280 sortByColumn(index, index == mSortColumnIndex);
281 }
282
283 void MultiListBox::redrawButtons()
284 {
285 size_t pos = 0;
286 for (auto& iter : mVectorColumnInfo)
287 {
288 if (pos == mSortColumnIndex)
289 {
290 if (mSortUp)
291 iter.button->setImageName("Up");
292 else
293 iter.button->setImageName("Down");
294 }
295 else
296 iter.button->setImageName("None");
297
298 iter.button->setCaption(iter.name);
299 pos++;
300 }
301 }
302
303 void MultiListBox::frameEntered(float _frame)
304 {
305 sortList();
306 }
307
308 void MultiListBox::frameAdvise(bool _advise)
309 {
310 if (_advise)
311 {
312 if (!mFrameAdvise)
313 {
314 MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate(this, &MultiListBox::frameEntered);
315 mFrameAdvise = true;
316 }
317 }
318 else
319 {
320 if (mFrameAdvise)
321 {
322 MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &MultiListBox::frameEntered);
323 mFrameAdvise = false;
324 }
325 }
326 }
327
328 Widget* MultiListBox::getOrCreateSeparator(size_t _index)
329 {
330 if (!mWidthSeparator || mSkinSeparator.empty())
331 return nullptr;
332 // последний столбик
333 if (_index == mVectorColumnInfo.size() - 1)
334 return nullptr;
335
336 while (_index >= mSeparators.size())
337 {
338 Widget* separator = _getClientWidget()->createWidget<Widget>(mSkinSeparator, IntCoord(), Align::Default);
339 mSeparators.push_back(separator);
340 }
341
342 return mSeparators[_index];
343 }
344
345 void MultiListBox::flipList()
346 {
347 if (ITEM_NONE == mSortColumnIndex)
348 return;
349
350 size_t last = mVectorColumnInfo.front().list->getItemCount();
351 if (0 == last)
352 return;
353 last--;
354 size_t first = 0;
355
356 while (first < last)
357 {
358 BiIndexBase::swapItemsBackAt(first, last);
359 for (auto& iter : mVectorColumnInfo)
360 {
361 iter.list->swapItemsAt(first, last);
362 }
363
364 first++;
365 last--;
366 }
367
368 updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
369 }
370
371 bool MultiListBox::compare(ListBox* _list, size_t _left, size_t _right)
372 {
373 bool result = false;
374 if (mSortUp)
375 std::swap(_left, _right);
376 if (requestOperatorLess.empty())
377 {
378 result = _list->getItemNameAt(_left) < _list->getItemNameAt(_right);
379 }
380 else
381 {
382#ifndef MYGUI_DONT_USE_OBSOLETE
383 requestOperatorLess.m_eventObsolete(
384 this,
385 mSortColumnIndex,
386 _list->getItemNameAt(_left),
387 _list->getItemNameAt(_right),
388 result);
389 requestOperatorLess.m_event(
390 this,
391 mSortColumnIndex,
394 result);
395#else
397 this,
398 mSortColumnIndex,
401 result);
402#endif
403 }
404 return result;
405 }
406
407 void MultiListBox::sortList()
408 {
409 if (ITEM_NONE == mSortColumnIndex)
410 return;
411
412 ListBox* list = mVectorColumnInfo[mSortColumnIndex].list;
413
414 size_t count = list->getItemCount();
415 if (0 == count)
416 return;
417
418 // shell sort
419 int first;
420 size_t last;
421 for (size_t step = count >> 1; step > 0; step >>= 1)
422 {
423 for (size_t i = 0; i < (count - step); i++)
424 {
425 first = (int)i;
426 while (first >= 0)
427 {
428 last = first + step;
429 if (compare(list, first, last))
430 {
431 BiIndexBase::swapItemsBackAt(first, last);
432 for (auto& iter : mVectorColumnInfo)
433 {
434 iter.list->swapItemsAt(first, last);
435 }
436 }
437 first--;
438 }
439 }
440 }
441
442 frameAdvise(false);
443
444 updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
445 }
446
447 void MultiListBox::insertItemAt(size_t _index, const UString& _name, Any _data)
448 {
449 MYGUI_ASSERT(!mVectorColumnInfo.empty(), "MultiListBox::insertItemAt");
450 MYGUI_ASSERT_RANGE_INSERT(_index, mVectorColumnInfo.front().list->getItemCount(), "MultiListBox::insertItemAt");
451 if (ITEM_NONE == _index)
452 _index = mVectorColumnInfo.front().list->getItemCount();
453
454 // если надо, то меняем выделенный элемент
455 // при сортировке, обновится
456 if ((mItemSelected != ITEM_NONE) && (_index <= mItemSelected))
457 mItemSelected++;
458
459 size_t index = BiIndexBase::insertItemAt(_index);
460
461 // вставляем во все поля пустые, а потом присваиваем первому
462 for (auto& iter : mVectorColumnInfo)
463 {
464 iter.list->insertItemAt(index, UString());
465 }
466 mVectorColumnInfo.front().list->setItemNameAt(index, _name);
467 mVectorColumnInfo.front().list->setItemDataAt(index, _data);
468
469 frameAdvise(true);
470 }
471
472 void MultiListBox::removeItemAt(size_t _index)
473 {
474 MYGUI_ASSERT(!mVectorColumnInfo.empty(), "MultiListBox::removeItemAt");
475 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::removeItemAt");
476
477 size_t index = BiIndexBase::removeItemAt(_index);
478
479 for (auto& iter : mVectorColumnInfo)
480 {
481 iter.list->removeItemAt(index);
482 }
483
484 // если надо, то меняем выделенный элемент
485 size_t count = mVectorColumnInfo.begin()->list->getItemCount();
486 if (count == 0)
487 mItemSelected = ITEM_NONE;
488 else if (mItemSelected != ITEM_NONE)
489 {
490 if (_index < mItemSelected)
491 mItemSelected--;
492 else if ((_index == mItemSelected) && (mItemSelected == count))
493 mItemSelected--;
494 }
495 updateBackSelected(BiIndexBase::convertToBack(mItemSelected));
496 }
497
498 void MultiListBox::swapItemsAt(size_t _index1, size_t _index2)
499 {
500 MYGUI_ASSERT(!mVectorColumnInfo.empty(), "MultiListBox::removeItemAt");
501 MYGUI_ASSERT_RANGE(_index1, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::swapItemsAt");
502 MYGUI_ASSERT_RANGE(_index2, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::swapItemsAt");
503
504 // при сортированном, меняем только индексы
505 BiIndexBase::swapItemsFaceAt(_index1, _index2);
506
507 // при несортированном, нужно наоборот, поменять только данные
508 // FIXME
509 }
510
511 void MultiListBox::setColumnDataAt(size_t _index, Any _data)
512 {
513 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.size(), "MultiListBox::setColumnDataAt");
514 mVectorColumnInfo[_index].data = std::move(_data);
515 }
516
517 void MultiListBox::setSubItemDataAt(size_t _column, size_t _index, Any _data)
518 {
519 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.begin()->list->getItemCount(), "MultiListBox::setSubItemDataAt");
520
521 size_t index = BiIndexBase::convertToBack(_index);
522 getSubItemAt(_column)->setItemDataAt(index, _data);
523 }
524
526 {
527 return mVectorColumnInfo.size();
528 }
529
530 void MultiListBox::addColumn(const UString& _name, int _width, Any _data)
531 {
532 insertColumnAt(ITEM_NONE, _name, _width, _data);
533 }
534
536 {
537 setColumnDataAt(_index, Any::Null);
538 }
539
540 void MultiListBox::addItem(const UString& _name, Any _data)
541 {
542 insertItemAt(ITEM_NONE, _name, _data);
543 }
544
545 void MultiListBox::setItemNameAt(size_t _index, const UString& _name)
546 {
547 setSubItemNameAt(0, _index, _name);
548 }
549
550 const UString& MultiListBox::getItemNameAt(size_t _index) const
551 {
552 return getSubItemNameAt(0, _index);
553 }
554
556 {
557 return mItemSelected;
558 }
559
564
565 void MultiListBox::setItemDataAt(size_t _index, Any _data)
566 {
567 setSubItemDataAt(0, _index, _data);
568 }
569
571 {
572 setItemDataAt(_index, Any::Null);
573 }
574
575 void MultiListBox::clearSubItemDataAt(size_t _column, size_t _index)
576 {
577 setSubItemDataAt(_column, _index, Any::Null);
578 }
579
580 ListBox* MultiListBox::getSubItemAt(size_t _column) const
581 {
582 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::getSubItemAt");
583 return mVectorColumnInfo[_column].list;
584 }
585
587 {
588 return getColumnCount();
589 }
590
596
597 void MultiListBox::_removeItemAt(size_t _index)
598 {
599 removeColumnAt(_index);
600 }
601
602 void MultiListBox::_setItemNameAt(size_t _index, const UString& _name)
603 {
604 setColumnNameAt(_index, _name);
605 }
606
607 const UString& MultiListBox::_getItemNameAt(size_t _index) const
608 {
609 return getColumnNameAt(_index);
610 }
611
612 void MultiListBox::insertColumnAt(size_t _column, const UString& _name, int _width, Any _data)
613 {
614 MYGUI_ASSERT_RANGE_INSERT(_column, mVectorColumnInfo.size(), "MultiListBox::insertColumnAt");
615 if (_column == ITEM_NONE)
616 _column = mVectorColumnInfo.size();
617
619
620 mVectorColumnInfo.back().width = _width;
621 mVectorColumnInfo.back().sizeType = ResizingPolicy::Fixed;
622 mVectorColumnInfo.back().name = _name;
623 mVectorColumnInfo.back().data = std::move(_data);
624 mVectorColumnInfo.back().button->setCaption(_name);
625
626 if (_column == (mVectorColumnInfo.size() - 1))
627 {
628 updateColumns();
629
630 mVectorColumnInfo.back().list->setScrollVisible(true);
631 }
632 else
633 {
634 _swapColumnsAt(_column, mVectorColumnInfo.size() - 1);
635 }
636 }
637
638 void MultiListBox::removeColumnAt(size_t _column)
639 {
640 MYGUI_ASSERT_RANGE(_column, mVectorColumnInfo.size(), "MultiListBox::removeColumnAt");
641
642 ColumnInfo& info = mVectorColumnInfo[_column];
643
645 }
646
647 void MultiListBox::swapColumnsAt(size_t _index1, size_t _index2)
648 {
649 MYGUI_ASSERT_RANGE(_index1, mVectorColumnInfo.size(), "MultiListBox::swapColumnsAt");
650 MYGUI_ASSERT_RANGE(_index2, mVectorColumnInfo.size(), "MultiListBox::swapColumnsAt");
651
652 _swapColumnsAt(_index1, _index2);
653 }
654
655 void MultiListBox::_swapColumnsAt(size_t _index1, size_t _index2)
656 {
657 if (_index1 == _index2)
658 return;
659
660 mVectorColumnInfo[_index1].list->setScrollVisible(false);
661 mVectorColumnInfo[_index2].list->setScrollVisible(false);
662
663 std::swap(mVectorColumnInfo[_index1], mVectorColumnInfo[_index2]);
664
665 updateColumns();
666
667 mVectorColumnInfo.back().list->setScrollVisible(true);
668 }
669
671 {
672 Base::onWidgetCreated(_widget);
673
674 MultiListItem* child = _widget->castType<MultiListItem>(false);
675 if (child != nullptr)
676 {
677 _wrapItem(child);
678 }
679 }
680
682 {
683 Base::onWidgetDestroy(_widget);
684
685 MultiListItem* child = _widget->castType<MultiListItem>(false);
686 if (child != nullptr)
687 {
688 _unwrapItem(child);
689 }
690 else
691 {
692 for (auto& item : mVectorColumnInfo)
693 {
694 if (item.button == _widget)
695 item.button = nullptr;
696 }
697 }
698 }
699
700 void MultiListBox::_wrapItem(MultiListItem* _item)
701 {
702 // скрываем у крайнего скролл
703 if (!mVectorColumnInfo.empty())
704 mVectorColumnInfo.back().list->setScrollVisible(false);
705 else
706 mSortColumnIndex = ITEM_NONE;
707
708 ColumnInfo column;
709 column.width = 0;
710 column.realWidth = 0;
711 column.sizeType = ResizingPolicy::Auto;
712
713 column.item = _item;
714 column.list = _item->createWidget<ListBox>(
715 mSkinList,
716 IntCoord(0, 0, _item->getWidth(), _item->getHeight()),
718 column.list->eventListChangePosition += newDelegate(this, &MultiListBox::notifyListChangePosition);
719 column.list->eventListMouseItemFocus += newDelegate(this, &MultiListBox::notifyListChangeFocus);
720 column.list->eventListChangeScroll += newDelegate(this, &MultiListBox::notifyListChangeScrollPosition);
721 column.list->eventListSelectAccept += newDelegate(this, &MultiListBox::notifyListSelectAccept);
722 column.list->eventNotifyItem += newDelegate(this, &MultiListBox::notifyListNotifyItem);
723
724 if (mHeaderPlace != nullptr)
725 column.button = mHeaderPlace->createWidget<Button>(mSkinButton, IntCoord(), Align::Default);
726 else
727 column.button = _getClientWidget()->createWidget<Button>(mSkinButton, IntCoord(), Align::Default);
728
729 column.button->eventMouseButtonClick += newDelegate(this, &MultiListBox::notifyButtonClick);
730
731 // если уже были столбики, то делаем то же колличество полей
732 if (!mVectorColumnInfo.empty())
733 {
734 size_t count = mVectorColumnInfo.front().list->getItemCount();
735 for (size_t pos = 0; pos < count; ++pos)
736 column.list->addItem(UString());
737 }
738
739 mVectorColumnInfo.push_back(column);
740
741 updateColumns();
742
743 // показываем скролл нового крайнего
744 mVectorColumnInfo.back().list->setScrollVisible(true);
745 }
746
747 void MultiListBox::_unwrapItem(MultiListItem* _item)
748 {
749 for (VectorColumnInfo::iterator item = mVectorColumnInfo.begin(); item != mVectorColumnInfo.end(); ++item)
750 {
751 if ((*item).item == _item)
752 {
753 if ((*item).button != nullptr)
755
756 mVectorColumnInfo.erase(item);
757 break;
758 }
759 }
760
761 if (mVectorColumnInfo.empty())
762 {
763 mSortColumnIndex = ITEM_NONE;
764 mItemSelected = ITEM_NONE;
765 }
766 else
767 {
768 mSortColumnIndex = ITEM_NONE;
769 mSortUp = true;
770 sortList();
771 }
772
773 updateColumns();
774
775 if (!mVectorColumnInfo.empty())
776 mVectorColumnInfo.back().list->setScrollVisible(true);
777 }
778
779 Widget* MultiListBox::_getItemAt(size_t _index) const
780 {
781 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.size(), "MultiListBox::_getItemAt");
782 return mVectorColumnInfo[_index].item;
783 }
784
786 {
787 setColumnNameAt(getColumnIndex(_item), _name);
788 }
789
791 {
792 return getColumnNameAt(getColumnIndex(_item));
793 }
794
796 {
797 for (size_t index = 0; index < mVectorColumnInfo.size(); ++index)
798 {
799 if (mVectorColumnInfo[index].item == _item)
800 return index;
801 }
802
803 return ITEM_NONE;
804 }
805
810
812 {
813 MYGUI_ASSERT_RANGE(_index, mVectorColumnInfo.size(), "MultiListBox::setColumnWidthAt");
814 mVectorColumnInfo[_index].sizeType = _value;
815 updateColumns();
816 }
817
819 {
820 setColumnWidthAt(getColumnIndex(_item), _width);
821 }
822
824 {
825 Base::setPosition(_point);
826 }
827
829 {
830 Base::setSize(_size);
831
832 if (getUpdateByResize())
833 updateColumns();
834 }
835
837 {
838 Base::setCoord(_coord);
839
840 if (getUpdateByResize())
841 updateColumns();
842 }
843
844 bool MultiListBox::getUpdateByResize() const
845 {
846 if (mWidgetEmpty != nullptr)
847 return true;
848
849 for (const auto& info : mVectorColumnInfo)
850 {
851 if (info.sizeType == ResizingPolicy::Fill)
852 return true;
853 }
854 return false;
855 }
856
857 int MultiListBox::getColumnWidth(
858 size_t _index,
859 int _freeSpace,
860 size_t _countStars,
861 size_t _lastIndexStar,
862 int _starWidth) const
863 {
864 const ColumnInfo& info = mVectorColumnInfo[_index];
865
866 if (info.sizeType == ResizingPolicy::Auto)
867 {
868 return info.realWidth;
869 }
870 if (info.sizeType == ResizingPolicy::Fixed)
871 {
872 return info.realWidth;
873 }
874 if (info.sizeType == ResizingPolicy::Fill)
875 {
876 if (_lastIndexStar == _index)
877 {
878 return _starWidth + _freeSpace - (_starWidth * _countStars);
879 }
880 return _starWidth;
881 }
882 return 0;
883 }
884
885 int MultiListBox::updateWidthColumns(size_t& _countStars, size_t& _lastIndexStar)
886 {
887 _countStars = 0;
888 _lastIndexStar = ITEM_NONE;
889
890 int width = 0;
891
892 for (size_t index = 0; index < mVectorColumnInfo.size(); ++index)
893 {
894 ColumnInfo& info = mVectorColumnInfo[index];
895
896 if (info.sizeType == ResizingPolicy::Auto)
897 {
898 info.realWidth =
899 info.button->getWidth() - info.button->getTextRegion().width + info.button->getTextSize().width;
900 }
901 else if (info.sizeType == ResizingPolicy::Fixed)
902 {
903 info.realWidth = info.width < 0 ? 0 : info.width;
904 }
905 else if (info.sizeType == ResizingPolicy::Fill)
906 {
907 info.realWidth = 0;
908 _countStars++;
909 _lastIndexStar = index;
910 }
911 else
912 {
913 info.realWidth = 0;
914 }
915
916 width += info.realWidth;
917 }
918
919 return width;
920 }
921
922 void MultiListBox::updateColumns()
923 {
924 size_t countStars = 0;
925 size_t lastIndexStar = ITEM_NONE;
926
927 int allColumnsWidth = updateWidthColumns(countStars, lastIndexStar);
928 int clientWidth = _getClientWidget()->getWidth();
929 int separatorsWidth = mVectorColumnInfo.empty() ? 0 : (mVectorColumnInfo.size() - 1) * mWidthSeparator;
930 int freeSpace = clientWidth - separatorsWidth - allColumnsWidth;
931 int starWidth = (countStars != 0 && freeSpace > 0) ? (freeSpace / countStars) : 0;
932
933 mWidthBar = 0;
934 for (size_t index = 0; index < mVectorColumnInfo.size(); ++index)
935 {
936 ColumnInfo& info = mVectorColumnInfo[index];
937
938 int columnWidth = getColumnWidth(index, freeSpace, countStars, lastIndexStar, starWidth);
939
940 if (mHeaderPlace != nullptr)
941 {
942 info.item->setCoord(mWidthBar, 0, columnWidth, _getClientWidget()->getHeight());
943 }
944 else
945 {
946 info.item
947 ->setCoord(mWidthBar, mHeightButton, columnWidth, _getClientWidget()->getHeight() - mHeightButton);
948 }
949
950 info.button->setCoord(mWidthBar, 0, columnWidth, getButtonHeight());
951 info.button->_setInternalData(index);
952
953 mWidthBar += columnWidth;
954
955 // промежуток между листами
956 Widget* separator = getOrCreateSeparator(index);
957 if (separator)
958 {
959 separator->setCoord(mWidthBar, 0, mWidthSeparator, _getClientWidget()->getHeight());
960 }
961
962 mWidthBar += mWidthSeparator;
963 }
964
965 redrawButtons();
966 updateOnlyEmpty();
967 }
968
969} // 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
void swapItemsBackAt(size_t _index1, size_t _index2)
size_t removeItemAt(size_t _index)
size_t insertItemAt(size_t _index)
size_t convertToBack(size_t _index) const
size_t convertToFace(size_t _index) const
void swapItemsFaceAt(size_t _index1, size_t _index2)
widget description should be here.
static Gui & getInstance()
Definition MyGUI_Gui.cpp:34
EventHandle_FrameEventDelegate eventFrameStart
Definition MyGUI_Gui.h:215
Type * castType(bool _throw=true)
widget description should be here.
const UString & getItemNameAt(size_t _index) const
Get item name from specified position.
EventPair< EventHandle_WidgetSizeT, EventHandle_ListPtrSizeT > eventListChangePosition
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 setItemDataAt(size_t _index, Any _data)
Replace an item data at a specified position.
void setItemNameAt(size_t _index, const UString &_name)
Replace an item name at a specified position.
size_t _getItemCount() const override
void setColumnWidthAt(size_t _column, int _width)
void addItem(const UString &_name, Any _data=Any::Null)
void onWidgetDestroy(Widget *_widget) override
void _removeItemAt(size_t _index) override
void insertItemAt(size_t _index, const UString &_name, Any _data=Any::Null)
void setColumnResizingPolicyAt(size_t _index, ResizingPolicy _value)
void setColumnWidth(MultiListItem *_item, int _width)
void _setItemNameAt(size_t _index, const UString &_name) override
void removeItemAt(size_t _index)
Remove item at a specified position.
void setCoord(const IntCoord &_coord) override
EventPair< EventHandle_MultiListPtrSizeTCUTFStringRefCUTFStringRefBoolRef, EventHandle_MultiListPtrSizeTSizeTSizeTBoolRef > requestOperatorLess
const UString & getItemNameAt(size_t _index) const
Get item name from specified position.
void setColumnDataAt(size_t _index, Any _data)
Replace an item data at a specified position.
EventPair< EventHandle_WidgetSizeT, EventHandle_MultiListPtrSizeT > eventListChangePosition
void sortByColumn(size_t _column, bool _backward=false)
const UString & _getItemNameAt(size_t _index) const override
void insertColumnAt(size_t _column, const UString &_name, int _width=0, Any _data=Any::Null)
void setItemNameAt(size_t _index, const UString &_name)
Replace an item name.
int getColumnWidthAt(size_t _column) const
void setSize(const IntSize &_size) override
EventPair< EventHandle_WidgetSizeT, EventHandle_MultiListPtrSizeT > eventListSelectAccept
size_t getColumnCount() const
Get number of columns.
void setSubItemDataAt(size_t _column, size_t _index, Any _data)
Replace an item data at a specified position.
void swapItemsAt(size_t _index1, size_t _index2)
Swap items at a specified positions.
void setSubItemNameAt(size_t _column, size_t _index, const UString &_name)
void onWidgetCreated(Widget *_widget) override
void removeColumnAt(size_t _column)
Widget * _getItemAt(size_t _index) const override
void setPosition(const IntPoint &_point) override
void clearItemDataAt(size_t _index)
Clear an item data at a specified position.
size_t findSubItemWith(size_t _column, const UString &_name)
void _addItem(const MyGUI::UString &_name) override
void clearColumnDataAt(size_t _index)
Clear an item data at a specified position.
void setItemDataAt(size_t _index, Any _data)
Replace an item data at a specified position.
void shutdownOverride() override
EventHandle_MultiListPtrCIBNotifyCellDataRef eventNotifyItem
void initialiseOverride() override
size_t getColumnIndex(const MultiListItem *_item) const
Get column index.
void setColumnNameAt(size_t _column, const UString &_name)
void addColumn(const UString &_name, int _width=0, Any _data=Any::Null)
const UString & getSubItemNameAt(size_t _column, size_t _index) const
size_t getIndexSelected() const
void setColumnName(MultiListItem *_item, const UString &_name)
void setColumnResizingPolicy(MultiListItem *_item, ResizingPolicy _value)
void clearSubItemDataAt(size_t _column, size_t _index)
Clear an item data at a specified position.
void setIndexSelected(size_t _index)
const UString & getColumnNameAt(size_t _column) const
void swapColumnsAt(size_t _index1, size_t _index2)
Swap columns at a specified positions.
const UString & getColumnName(const MultiListItem *_item) const
widget description should be here.
A UTF-16 string with implicit conversion to/from std::string and std::wstring.
const code_point * data() const
returns a pointer to the first character in the current string
bool isUserString(std::string_view _key) const
std::string_view getUserString(std::string_view _key) const
ValueType * _getInternalData(bool _throw=true) const
widget description should be here.
virtual void setVisible(bool _value)
void assignWidget(T *&_widget, std::string_view _name)
T * createWidget(std::string_view _skin, const IntCoord &_coord, Align _align, std::string_view _name={})
void setCoord(const IntCoord &_coord) override
Widget * _getClientWidget()
If there is client widget return it, otherwise return this.
EventHandle_WidgetVoid eventMouseButtonClick
static WidgetManager & getInstance()
void destroyWidget(Widget *_widget)
T parseValue(std::string_view _value)
constexpr size_t ITEM_NONE
types::TCoord< int > IntCoord
Definition MyGUI_Types.h:36
delegates::DelegateFunction< Args... > * newDelegate(void(*_func)(Args... args))