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