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