MyGUI  3.2.1
MyGUI_ComboBox.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_ComboBox.h"
10 #include "MyGUI_InputManager.h"
11 #include "MyGUI_WidgetManager.h"
12 #include "MyGUI_Gui.h"
13 #include "MyGUI_ListBox.h"
14 #include "MyGUI_Button.h"
15 #include "MyGUI_ResourceSkin.h"
16 #include "MyGUI_LayerManager.h"
17 
18 namespace MyGUI
19 {
20 
21  const float COMBO_ALPHA_MAX = ALPHA_MAX;
22  const float COMBO_ALPHA_MIN = ALPHA_MIN;
23  const float COMBO_ALPHA_COEF = 4.0f;
24 
26  mButton(nullptr),
27  mList(nullptr),
28  mListShow(false),
29  mMaxListLength(-1),
30  mItemIndex(ITEM_NONE),
31  mModeDrop(false),
32  mDropMouse(false),
33  mShowSmooth(false),
34  mFlowDirection(FlowDirection::TopToBottom)
35  {
36  }
37 
39  {
41 
43  assignWidget(mButton, "Button");
44  if (mButton != nullptr)
45  {
46  mButton->eventMouseButtonPressed += newDelegate(this, &ComboBox::notifyButtonPressed);
47  }
48 
50  assignWidget(mList, "List");
51 
52  if (mList == nullptr)
53  {
54  std::string list_skin = getUserString("ListSkin");
55  std::string list_layer = getUserString("ListLayer");
56 
57  mList = static_cast<ListBox*>(_createSkinWidget(WidgetStyle::Popup, ListBox::getClassTypeName(), list_skin, IntCoord(), Align::Default, list_layer));
58  }
59 
60  if (mList != nullptr)
61  {
62  mList->setVisible(false);
63  mList->eventKeyLostFocus += newDelegate(this, &ComboBox::notifyListLostFocus);
64  mList->eventListSelectAccept += newDelegate(this, &ComboBox::notifyListSelectAccept);
65  mList->eventListMouseItemActivate += newDelegate(this, &ComboBox::notifyListMouseItemActivate);
66  mList->eventListChangePosition += newDelegate(this, &ComboBox::notifyListChangePosition);
67 
68  mList->setNeedToolTip(true);
69  mList->eventToolTip += newDelegate(this, &ComboBox::notifyToolTip);
70  }
71 
72  // подписываем дочерние классы на скролл
73  if (mClient != nullptr)
74  {
75  mClient->eventMouseWheel += newDelegate(this, &ComboBox::notifyMouseWheel);
76  mClient->eventMouseButtonPressed += newDelegate(this, &ComboBox::notifyMousePressed);
77 
78  mClient->setNeedToolTip(true);
79  mClient->eventToolTip += newDelegate(this, &ComboBox::notifyToolTip);
80  }
81 
82  // подписываемся на изменения текста
83  eventEditTextChange += newDelegate(this, &ComboBox::notifyEditTextChange);
84  }
85 
87  {
88  mList = nullptr;
89  mButton = nullptr;
90  mClient = nullptr;
91 
93  }
94 
95  void ComboBox::notifyButtonPressed(Widget* _sender, int _left, int _top, MouseButton _id)
96  {
97  if (MouseButton::Left != _id)
98  return;
99 
100  mDropMouse = true;
101 
102  if (mListShow)
103  hideList();
104  else
105  showList();
106  }
107 
108  void ComboBox::notifyListLostFocus(Widget* _sender, Widget* _new)
109  {
110  if (mDropMouse)
111  {
112  mDropMouse = false;
114 
115  // кнопка сама уберет список
116  if (focus == mButton)
117  return;
118 
119  // в режиме дропа все окна учавствуют
120  if (mModeDrop && focus == mClient)
121  return;
122  }
123 
124  hideList();
125  }
126 
127  void ComboBox::notifyListSelectAccept(ListBox* _widget, size_t _position)
128  {
129  mItemIndex = _position;
130  Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
131 
132  mDropMouse = false;
134 
135  if (mModeDrop)
136  {
137  _resetContainer(false);
138 
139  eventComboAccept.m_eventObsolete(this);
140  eventComboAccept.m_event(this, mItemIndex);
141  }
142  }
143 
144  void ComboBox::notifyListChangePosition(ListBox* _widget, size_t _position)
145  {
146  mItemIndex = _position;
147 
148  _resetContainer(false);
149 
150  eventComboChangePosition(this, _position);
151  }
152 
154  {
155  Base::onKeyButtonPressed(_key, _char);
156 
157  // при нажатии вниз, показываем лист
158  if (_key == KeyCode::ArrowDown)
159  {
160  // выкидываем список только если мыша свободна
161  if (!InputManager::getInstance().isCaptureMouse())
162  {
163  showList();
164  }
165  }
166  // нажат ввод в окне редиктирования
167  else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
168  {
169  _resetContainer(false);
170 
171  eventComboAccept.m_eventObsolete(this);
172  eventComboAccept.m_event(this, mItemIndex);
173  }
174  }
175 
176  void ComboBox::notifyListMouseItemActivate(ListBox* _widget, size_t _position)
177  {
178  mItemIndex = _position;
179  Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
180 
182 
183  if (mModeDrop)
184  {
185  _resetContainer(false);
186 
187  eventComboAccept.m_eventObsolete(this);
188  eventComboAccept.m_event(this, mItemIndex);
189  }
190  }
191 
192  void ComboBox::notifyMouseWheel(Widget* _sender, int _rel)
193  {
194  if (mList->getItemCount() == 0)
195  return;
197  return;
199  return;
200 
201  if (_rel > 0)
202  {
203  if (mItemIndex != 0)
204  {
205  if (mItemIndex == ITEM_NONE)
206  mItemIndex = 0;
207  else
208  mItemIndex --;
209  Base::setCaption(mList->getItemNameAt(mItemIndex));
210  mList->setIndexSelected(mItemIndex);
211  mList->beginToItemAt(mItemIndex);
212 
213  _resetContainer(false);
214 
215  eventComboChangePosition(this, mItemIndex);
216  }
217  }
218  else if (_rel < 0)
219  {
220  if ((mItemIndex + 1) < mList->getItemCount())
221  {
222  if (mItemIndex == ITEM_NONE)
223  mItemIndex = 0;
224  else
225  mItemIndex ++;
226  Base::setCaption(mList->getItemNameAt(mItemIndex));
227  mList->setIndexSelected(mItemIndex);
228  mList->beginToItemAt(mItemIndex);
229 
230  _resetContainer(false);
231 
232  eventComboChangePosition(this, mItemIndex);
233  }
234  }
235  }
236 
237  void ComboBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
238  {
239  // обязательно отдаем отцу, а то мы у него в наглую отняли
240  Base::notifyMousePressed(_sender, _left, _top, _id);
241 
242  mDropMouse = true;
243 
244  // показываем список
245  if (mModeDrop)
246  notifyButtonPressed(nullptr, _left, _top, _id);
247  }
248 
249  void ComboBox::notifyEditTextChange(EditBox* _sender)
250  {
251  // сбрасываем выделенный элемент
252  if (ITEM_NONE != mItemIndex)
253  {
254  mItemIndex = ITEM_NONE;
255  mList->setIndexSelected(mItemIndex);
256  mList->beginToItemFirst();
257 
258  _resetContainer(false);
259 
260  eventComboChangePosition(this, mItemIndex);
261  }
262  }
263 
264  void ComboBox::showList()
265  {
266  // пустой список не показываем
267  if (mList->getItemCount() == 0)
268  return;
269 
270  mListShow = true;
271 
272  IntCoord coord = calculateListPosition();
273  mList->setCoord(coord);
274 
275  if (mShowSmooth)
276  {
277  ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MAX, COMBO_ALPHA_COEF, true);
278  ControllerManager::getInstance().addItem(mList, controller);
279  }
280  else
281  {
282  mList->setVisible(true);
283  }
284 
286  }
287 
288  void ComboBox::actionWidgetHide(Widget* _widget, ControllerItem* _controller)
289  {
290  _widget->setVisible(false);
291  _widget->setEnabled(true);
292  }
293 
294  void ComboBox::hideList()
295  {
296  mListShow = false;
297 
298  if (mShowSmooth)
299  {
300  ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MIN, COMBO_ALPHA_COEF, false);
301  controller->eventPostAction += newDelegate(this, &ComboBox::actionWidgetHide);
302  ControllerManager::getInstance().addItem(mList, controller);
303  }
304  else
305  {
306  mList->setVisible(false);
307  }
308  }
309 
310  void ComboBox::setIndexSelected(size_t _index)
311  {
312  MYGUI_ASSERT_RANGE_AND_NONE(_index, mList->getItemCount(), "ComboBox::setIndexSelected");
313  mItemIndex = _index;
314  mList->setIndexSelected(_index);
315  if (_index == ITEM_NONE)
316  {
317  Base::setCaption("");
318  return;
319  }
320  Base::setCaption(mList->getItemNameAt(_index));
321  Base::updateView(); // hook for update
322  }
323 
324  void ComboBox::setItemNameAt(size_t _index, const UString& _name)
325  {
326  mList->setItemNameAt(_index, _name);
327  mItemIndex = ITEM_NONE;//FIXME
328  mList->setIndexSelected(mItemIndex);//FIXME
329  }
330 
331  void ComboBox::setItemDataAt(size_t _index, Any _data)
332  {
333  mList->setItemDataAt(_index, _data);
334  mItemIndex = ITEM_NONE;//FIXME
335  mList->setIndexSelected(mItemIndex);//FIXME
336  }
337 
338  void ComboBox::insertItemAt(size_t _index, const UString& _item, Any _data)
339  {
340  mList->insertItemAt(_index, _item, _data);
341  mItemIndex = ITEM_NONE;//FIXME
342  mList->setIndexSelected(mItemIndex);//FIXME
343  }
344 
345  void ComboBox::removeItemAt(size_t _index)
346  {
347  mList->removeItemAt(_index);
348  mItemIndex = ITEM_NONE;//FIXME
349  mList->clearIndexSelected();//FIXME
350  }
351 
353  {
354  mItemIndex = ITEM_NONE;//FIXME
355  mList->removeAllItems();//FIXME заново созданные строки криво стоят
356  }
357 
358  void ComboBox::setComboModeDrop(bool _drop)
359  {
360  mModeDrop = _drop;
361  setEditStatic(mModeDrop);
362  }
363 
364  ControllerFadeAlpha* ComboBox::createControllerFadeAlpha(float _alpha, float _coef, bool _enable)
365  {
367  ControllerFadeAlpha* controller = item->castType<ControllerFadeAlpha>();
368 
369  controller->setAlpha(_alpha);
370  controller->setCoef(_coef);
371  controller->setEnabled(_enable);
372 
373  return controller;
374  }
375 
377  {
378  return mList->findItemIndexWith(_name);
379  }
380 
382  {
383  mFlowDirection = _value;
384  }
385 
386  IntCoord ComboBox::calculateListPosition()
387  {
388  int length = 0;
389  if (mFlowDirection.isVertical())
390  length = mList->getOptimalHeight();
391  else
392  length = mMaxListLength;
393 
394  if (mMaxListLength > 0 && length > mMaxListLength)
395  length = mMaxListLength;
396 
397  // берем глобальные координаты выджета
398  IntCoord coord = getAbsoluteCoord();
399  // размер леера
400  IntSize sizeView = mList->getParentSize();
401 
402  if (mFlowDirection == FlowDirection::TopToBottom)
403  {
404  if ((coord.bottom() + length) <= sizeView.height)
405  coord.top += coord.height;
406  else
407  coord.top -= length;
408  coord.height = length;
409  }
410  else if (mFlowDirection == FlowDirection::BottomToTop)
411  {
412  if ((coord.top - length) >= 0)
413  coord.top -= length;
414  else
415  coord.top += coord.height;
416  coord.height = length;
417  }
418  else if (mFlowDirection == FlowDirection::LeftToRight)
419  {
420  if ((coord.right() + length) <= sizeView.width)
421  coord.left += coord.width;
422  else
423  coord.left -= length;
424  coord.width = length;
425  }
426  else if (mFlowDirection == FlowDirection::RightToLeft)
427  {
428  if ((coord.left - length) >= 0)
429  coord.left -= length;
430  else
431  coord.left += coord.width;
432  coord.width = length;
433  }
434 
435  return coord;
436  }
437 
438  void ComboBox::setPropertyOverride(const std::string& _key, const std::string& _value)
439  {
441  if (_key == "ModeDrop")
442  setComboModeDrop(utility::parseValue<bool>(_value));
443 
445  else if (_key == "FlowDirection")
446  setFlowDirection(utility::parseValue<FlowDirection>(_value));
447 
449  else if (_key == "MaxListLength")
450  setMaxListLength(utility::parseValue<int>(_value));
451 
453  else if (_key == "SmoothShow")
454  setSmoothShow(utility::parseValue<bool>(_value));
455 
456  // не коментировать
457  else if (_key == "AddItem")
458  addItem(_value);
459 
460  else
461  {
462  Base::setPropertyOverride(_key, _value);
463  return;
464  }
465 
466  eventChangeProperty(this, _key, _value);
467  }
468 
469  size_t ComboBox::getItemCount() const
470  {
471  return mList->getItemCount();
472  }
473 
474  void ComboBox::addItem(const UString& _name, Any _data)
475  {
476  return insertItemAt(ITEM_NONE, _name, _data);
477  }
478 
480  {
481  return mItemIndex;
482  }
483 
485  {
487  }
488 
489  void ComboBox::clearItemDataAt(size_t _index)
490  {
491  setItemDataAt(_index, Any::Null);
492  }
493 
494  const UString& ComboBox::getItemNameAt(size_t _index)
495  {
496  return mList->getItemNameAt(_index);
497  }
498 
499  void ComboBox::beginToItemAt(size_t _index)
500  {
501  mList->beginToItemAt(_index);
502  }
503 
505  {
506  if (getItemCount())
507  beginToItemAt(0);
508  }
509 
511  {
512  if (getItemCount())
514  }
515 
517  {
518  if (getIndexSelected() != ITEM_NONE)
520  }
521 
523  {
524  return mModeDrop;
525  }
526 
527  void ComboBox::setSmoothShow(bool _value)
528  {
529  mShowSmooth = _value;
530  }
531 
533  {
534  return mShowSmooth;
535  }
536 
537  void ComboBox::setMaxListLength(int _value)
538  {
539  mMaxListLength = _value;
540  }
541 
543  {
544  return mMaxListLength;
545  }
546 
548  {
549  return mFlowDirection;
550  }
551 
552  void ComboBox::notifyToolTip(Widget* _sender, const ToolTipInfo& _info)
553  {
554  if (getNeedToolTip())
555  eventToolTip(this, _info);
556  }
557 
559  {
560  return getItemCount();
561  }
562 
564  {
565  addItem(_name);
566  }
567 
568  void ComboBox::_removeItemAt(size_t _index)
569  {
570  removeItemAt(_index);
571  }
572 
573  void ComboBox::_setItemNameAt(size_t _index, const UString& _name)
574  {
575  setItemNameAt(_index, _name);
576  }
577 
578  const UString& ComboBox::_getItemNameAt(size_t _index)
579  {
580  return getItemNameAt(_index);
581  }
582 
583  void ComboBox::_resetContainer(bool _update)
584  {
585  Base::_resetContainer(_update);
586  if (mList != nullptr)
587  mList->_resetContainer(_update);
588  }
589 
590 } // namespace MyGUI