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