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