MyGUI  3.4.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->setActivateOnClick(true);
63 
64  mList->setVisible(false);
65  mList->eventKeyLostFocus += newDelegate(this, &ComboBox::notifyListLostFocus);
66  mList->eventListSelectAccept += newDelegate(this, &ComboBox::notifyListSelectAccept);
67  mList->eventListMouseItemActivate += newDelegate(this, &ComboBox::notifyListMouseItemActivate);
68  mList->eventListChangePosition += newDelegate(this, &ComboBox::notifyListChangePosition);
69 
70  mList->setNeedToolTip(true);
71  mList->eventToolTip += newDelegate(this, &ComboBox::notifyToolTip);
72  }
73 
74  // подписываем дочерние классы на скролл
75  if (mScrollViewClient != nullptr)
76  {
77  mScrollViewClient->eventMouseWheel += newDelegate(this, &ComboBox::notifyMouseWheel);
78  mScrollViewClient->eventMouseButtonPressed += newDelegate(this, &ComboBox::notifyMousePressed);
79 
81  mScrollViewClient->eventToolTip += newDelegate(this, &ComboBox::notifyToolTip);
82  }
83 
84  // подписываемся на изменения текста
85  eventEditTextChange += newDelegate(this, &ComboBox::notifyEditTextChange);
86  }
87 
89  {
90  mList = nullptr;
91  mButton = nullptr;
92 
94  }
95 
96  void ComboBox::notifyButtonPressed(Widget* _sender, int _left, int _top, MouseButton _id)
97  {
98  if (MouseButton::Left != _id)
99  return;
100 
101  mDropMouse = true;
102 
103  if (mListShow)
104  hideList();
105  else
106  showList();
107  }
108 
109  void ComboBox::notifyListLostFocus(Widget* _sender, Widget* _new)
110  {
111  if (mDropMouse)
112  {
113  mDropMouse = false;
115 
116  // кнопка сама уберет список
117  if (focus == mButton)
118  return;
119 
120  // в режиме дропа все окна учавствуют
121  if (mModeDrop && focus == mScrollViewClient)
122  return;
123  }
124 
125  hideList();
126  }
127 
128  void ComboBox::notifyListSelectAccept(ListBox* _widget, size_t _position)
129  {
130  mItemIndex = _position;
131  Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
132 
133  mDropMouse = false;
135 
136  if (mModeDrop)
137  {
138  _resetContainer(false);
139 
140  eventComboAccept.m_eventObsolete(this);
141  eventComboAccept.m_event(this, mItemIndex);
142  }
143  }
144 
145  void ComboBox::notifyListChangePosition(ListBox* _widget, size_t _position)
146  {
147  mItemIndex = _position;
148 
149  _resetContainer(false);
150 
151  eventComboChangePosition(this, _position);
152  }
153 
155  {
156  Base::onKeyButtonPressed(_key, _char);
157 
158  // при нажатии вниз, показываем лист
159  if (_key == KeyCode::ArrowDown)
160  {
161  // выкидываем список только если мыша свободна
162  if (!InputManager::getInstance().isCaptureMouse())
163  {
164  showList();
165  }
166  }
167  // нажат ввод в окне редиктирования
168  else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
169  {
170  _resetContainer(false);
171 
172  eventComboAccept.m_eventObsolete(this);
173  eventComboAccept.m_event(this, mItemIndex);
174  }
175  }
176 
177  void ComboBox::notifyListMouseItemActivate(ListBox* _widget, size_t _position)
178  {
179  mItemIndex = _position;
180  Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
181 
183 
184  if (mModeDrop)
185  {
186  _resetContainer(false);
187 
188  eventComboAccept.m_eventObsolete(this);
189  eventComboAccept.m_event(this, mItemIndex);
190  }
191  }
192 
193  void ComboBox::notifyMouseWheel(Widget* _sender, int _rel)
194  {
195  if (mList->getItemCount() == 0)
196  return;
197  if (InputManager::getInstance().getKeyFocusWidget() != this)
198  return;
199  if (InputManager::getInstance().isCaptureMouse())
200  return;
201 
202  if (_rel > 0)
203  {
204  if (mItemIndex != 0)
205  {
206  if (mItemIndex == ITEM_NONE)
207  mItemIndex = 0;
208  else
209  mItemIndex --;
210  Base::setCaption(mList->getItemNameAt(mItemIndex));
211  mList->setIndexSelected(mItemIndex);
212  mList->beginToItemAt(mItemIndex);
213 
214  _resetContainer(false);
215 
216  eventComboChangePosition(this, mItemIndex);
217  }
218  }
219  else if (_rel < 0)
220  {
221  if ((mItemIndex + 1) < mList->getItemCount())
222  {
223  if (mItemIndex == ITEM_NONE)
224  mItemIndex = 0;
225  else
226  mItemIndex ++;
227  Base::setCaption(mList->getItemNameAt(mItemIndex));
228  mList->setIndexSelected(mItemIndex);
229  mList->beginToItemAt(mItemIndex);
230 
231  _resetContainer(false);
232 
233  eventComboChangePosition(this, mItemIndex);
234  }
235  }
236  }
237 
238  void ComboBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
239  {
240  // обязательно отдаем отцу, а то мы у него в наглую отняли
241  Base::notifyMousePressed(_sender, _left, _top, _id);
242 
243  mDropMouse = true;
244 
245  // показываем список
246  if (mModeDrop)
247  notifyButtonPressed(nullptr, _left, _top, _id);
248  }
249 
250  void ComboBox::notifyEditTextChange(EditBox* _sender)
251  {
252  // сбрасываем выделенный элемент
253  if (ITEM_NONE != mItemIndex)
254  {
255  mItemIndex = ITEM_NONE;
256  mList->setIndexSelected(mItemIndex);
257  mList->beginToItemFirst();
258 
259  _resetContainer(false);
260 
261  eventComboChangePosition(this, mItemIndex);
262  }
263  }
264 
265  void ComboBox::showList()
266  {
267  // пустой список не показываем
268  if (mList->getItemCount() == 0)
269  return;
270 
271  if (mListShow)
272  return;
273  mListShow = true;
274 
275  IntCoord coord = calculateListPosition();
276  mList->setCoord(coord);
277 
278  if (mShowSmooth)
279  {
280  ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MAX, COMBO_ALPHA_COEF, true);
281  ControllerManager::getInstance().addItem(mList, controller);
282  }
283  else
284  {
285  mList->setVisible(true);
286  }
287 
289  }
290 
291  void ComboBox::actionWidgetHide(Widget* _widget, ControllerItem* _controller)
292  {
293  _widget->setVisible(false);
294  _widget->setEnabled(true);
295  }
296 
297  void ComboBox::hideList()
298  {
299  if (!mListShow)
300  return;
301  mListShow = false;
302 
303  if (mShowSmooth)
304  {
305  ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MIN, COMBO_ALPHA_COEF, false);
306  controller->eventPostAction += newDelegate(this, &ComboBox::actionWidgetHide);
307  ControllerManager::getInstance().addItem(mList, controller);
308  }
309  else
310  {
311  mList->setVisible(false);
312  }
313  }
314 
315  void ComboBox::setIndexSelected(size_t _index)
316  {
317  MYGUI_ASSERT_RANGE_AND_NONE(_index, mList->getItemCount(), "ComboBox::setIndexSelected");
318  mItemIndex = _index;
319  mList->setIndexSelected(_index);
320  if (_index == ITEM_NONE)
321  {
322  Base::setCaption("");
323  return;
324  }
325  Base::setCaption(mList->getItemNameAt(_index));
326  Base::updateView(); // hook for update
327  }
328 
329  void ComboBox::setItemNameAt(size_t _index, const UString& _name)
330  {
331  mList->setItemNameAt(_index, _name);
332  mItemIndex = ITEM_NONE;//FIXME
333  mList->setIndexSelected(mItemIndex);//FIXME
334  }
335 
336  void ComboBox::setItemDataAt(size_t _index, Any _data)
337  {
338  mList->setItemDataAt(_index, _data);
339  mItemIndex = ITEM_NONE;//FIXME
340  mList->setIndexSelected(mItemIndex);//FIXME
341  }
342 
343  void ComboBox::insertItemAt(size_t _index, const UString& _item, Any _data)
344  {
345  mList->insertItemAt(_index, _item, _data);
346  mItemIndex = ITEM_NONE;//FIXME
347  mList->setIndexSelected(mItemIndex);//FIXME
348  }
349 
350  void ComboBox::removeItemAt(size_t _index)
351  {
352  mList->removeItemAt(_index);
353  mItemIndex = ITEM_NONE;//FIXME
354  mList->clearIndexSelected();//FIXME
355  }
356 
358  {
359  mItemIndex = ITEM_NONE;//FIXME
360  mList->removeAllItems();//FIXME заново созданные строки криво стоят
361  }
362 
363  void ComboBox::setComboModeDrop(bool _drop)
364  {
365  mModeDrop = _drop;
366  setEditStatic(mModeDrop);
367  }
368 
369  ControllerFadeAlpha* ComboBox::createControllerFadeAlpha(float _alpha, float _coef, bool _enable)
370  {
372  ControllerFadeAlpha* controller = item->castType<ControllerFadeAlpha>();
373 
374  controller->setAlpha(_alpha);
375  controller->setCoef(_coef);
376  controller->setEnabled(_enable);
377 
378  return controller;
379  }
380 
382  {
383  return mList->findItemIndexWith(_name);
384  }
385 
387  {
388  mFlowDirection = _value;
389  }
390 
391  IntCoord ComboBox::calculateListPosition()
392  {
393  int length = 0;
394  if (mFlowDirection.isVertical())
395  length = mList->getOptimalHeight();
396  else
397  length = mMaxListLength;
398 
399  if (mMaxListLength > 0 && length > mMaxListLength)
400  length = mMaxListLength;
401 
402  // берем глобальные координаты выджета
403  IntCoord coord = getAbsoluteCoord();
404  // размер леера
405  IntSize sizeView = mList->getParentSize();
406 
407  if (mFlowDirection == FlowDirection::TopToBottom)
408  {
409  if ((coord.bottom() + length) <= sizeView.height)
410  coord.top += coord.height;
411  else
412  coord.top -= length;
413  coord.height = length;
414  }
415  else if (mFlowDirection == FlowDirection::BottomToTop)
416  {
417  if ((coord.top - length) >= 0)
418  coord.top -= length;
419  else
420  coord.top += coord.height;
421  coord.height = length;
422  }
423  else if (mFlowDirection == FlowDirection::LeftToRight)
424  {
425  if ((coord.right() + length) <= sizeView.width)
426  coord.left += coord.width;
427  else
428  coord.left -= length;
429  coord.width = length;
430  }
431  else if (mFlowDirection == FlowDirection::RightToLeft)
432  {
433  if ((coord.left - length) >= 0)
434  coord.left -= length;
435  else
436  coord.left += coord.width;
437  coord.width = length;
438  }
439 
440  return coord;
441  }
442 
443  void ComboBox::setPropertyOverride(const std::string& _key, const std::string& _value)
444  {
446  if (_key == "ModeDrop")
447  setComboModeDrop(utility::parseValue<bool>(_value));
448 
450  else if (_key == "FlowDirection")
451  setFlowDirection(utility::parseValue<FlowDirection>(_value));
452 
454  else if (_key == "MaxListLength")
455  setMaxListLength(utility::parseValue<int>(_value));
456 
458  else if (_key == "SmoothShow")
459  setSmoothShow(utility::parseValue<bool>(_value));
460 
461  // не коментировать
462  else if (_key == "AddItem")
463  addItem(_value);
464 
465  else
466  {
467  Base::setPropertyOverride(_key, _value);
468  return;
469  }
470 
471  eventChangeProperty(this, _key, _value);
472  }
473 
474  size_t ComboBox::getItemCount() const
475  {
476  return mList->getItemCount();
477  }
478 
479  void ComboBox::addItem(const UString& _name, Any _data)
480  {
481  return insertItemAt(ITEM_NONE, _name, _data);
482  }
483 
485  {
486  return mItemIndex;
487  }
488 
490  {
492  }
493 
494  void ComboBox::clearItemDataAt(size_t _index)
495  {
496  setItemDataAt(_index, Any::Null);
497  }
498 
499  const UString& ComboBox::getItemNameAt(size_t _index) const
500  {
501  return mList->getItemNameAt(_index);
502  }
503 
504  void ComboBox::beginToItemAt(size_t _index)
505  {
506  mList->beginToItemAt(_index);
507  }
508 
510  {
511  if (getItemCount())
512  beginToItemAt(0);
513  }
514 
516  {
517  if (getItemCount())
519  }
520 
522  {
523  if (getIndexSelected() != ITEM_NONE)
525  }
526 
528  {
529  return mModeDrop;
530  }
531 
532  void ComboBox::setSmoothShow(bool _value)
533  {
534  mShowSmooth = _value;
535  }
536 
538  {
539  return mShowSmooth;
540  }
541 
542  void ComboBox::setMaxListLength(int _value)
543  {
544  mMaxListLength = _value;
545  }
546 
548  {
549  return mMaxListLength;
550  }
551 
553  {
554  return mFlowDirection;
555  }
556 
557  void ComboBox::notifyToolTip(Widget* _sender, const ToolTipInfo& _info)
558  {
559  if (getNeedToolTip())
560  eventToolTip(this, _info);
561  }
562 
563  size_t ComboBox::_getItemCount() const
564  {
565  return getItemCount();
566  }
567 
569  {
570  addItem(_name);
571  }
572 
573  void ComboBox::_removeItemAt(size_t _index)
574  {
575  removeItemAt(_index);
576  }
577 
578  void ComboBox::_setItemNameAt(size_t _index, const UString& _name)
579  {
580  setItemNameAt(_index, _name);
581  }
582 
583  const UString& ComboBox::_getItemNameAt(size_t _index) const
584  {
585  return getItemNameAt(_index);
586  }
587 
588  void ComboBox::_resetContainer(bool _update)
589  {
590  Base::_resetContainer(_update);
591  if (mList != nullptr)
592  mList->_resetContainer(_update);
593  }
594 
595 } // namespace MyGUI
#define MYGUI_ASSERT_RANGE_AND_NONE(index, size, owner)
static AnyEmpty Null
Definition: MyGUI_Any.h:59
void addItem(const UString &_name, Any _data=Any::Null)
Add an item to the end of a array.
void beginToItemSelected()
Move all elements so selected becomes visible.
EventPair< EventHandle_WidgetVoid, EventHandle_ComboBoxPtrSizeT > eventComboAccept
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 _setItemNameAt(size_t _index, const UString &_name) override
void clearIndexSelected()
Clear item selection.
void setItemNameAt(size_t _index, const UString &_name)
Replace an item name at a specified position.
void setIndexSelected(size_t _index)
Select specified _index.
void removeAllItems()
Remove all items.
void _addItem(const MyGUI::UString &_name) override
void setComboModeDrop(bool _value)
Set drop list mode (text can not be edited)
void onKeyButtonPressed(KeyCode _key, Char _char) override
const UString & _getItemNameAt(size_t _index) const override
void _removeItemAt(size_t _index) override
void shutdownOverride() override
size_t getIndexSelected() const
Get index of selected item (ITEM_NONE if none selected)
void beginToItemAt(size_t _index)
Move all elements so specified becomes visible.
bool getSmoothShow() const
Get smooth show of list flag.
void setFlowDirection(FlowDirection _value)
Set direction, where drop down list appears (TopToBottom by default).
void beginToItemLast()
Move all elements so last becomes visible.
void setMaxListLength(int _value)
Get max list length.
void insertItemAt(size_t _index, const UString &_name, Any _data=Any::Null)
Insert an item into a array at a specified position.
void initialiseOverride() override
bool getComboModeDrop() const
Get drop list mode flag.
EventPair< EventHandle_WidgetSizeT, EventHandle_ComboBoxPtrSizeT > eventComboChangePosition
void setSmoothShow(bool _value)
Set smooth show of list.
void setItemDataAt(size_t _index, Any _data)
Replace an item data at a specified position.
size_t _getItemCount() const override
void removeItemAt(size_t _index)
Remove item at a specified position.
void clearItemDataAt(size_t _index)
Clear an item data at a specified position.
void _resetContainer(bool _update) override
void setPropertyOverride(const std::string &_key, const std::string &_value) override
int getMaxListLength() const
Set max list length.
void beginToItemFirst()
Move all elements so first becomes visible.
size_t getItemCount() const
Get number of items.
FlowDirection getFlowDirection() const
Get direction, where drop down list appears.
const UString & getItemNameAt(size_t _index) const
Get item name from specified position.
static const std::string & getClassTypeName()
ControllerItem * createItem(const std::string &_type)
static ControllerManager & getInstance()
void addItem(Widget *_widget, ControllerItem *_item)
void setEditStatic(bool _value)
EventPair< EventHandle_WidgetVoid, EventHandle_EditPtr > eventEditTextChange
void setCaption(const UString &_value) override
Type * castType(bool _throw=true)
Definition: MyGUI_IObject.h:18
void setKeyFocusWidget(Widget *_widget)
Widget * getMouseFocusWidget() const
static InputManager & getInstance()
widget description should be here.
Definition: MyGUI_ListBox.h:31
void beginToItemAt(size_t _index)
Move all elements so specified becomes visible.
void _resetContainer(bool _update) override
const UString & getItemNameAt(size_t _index) const
Get item name from specified position.
void setActivateOnClick(bool activateOnClick)
void clearIndexSelected()
size_t getItemCount() const
Get number of items.
int getOptimalHeight() const
Return optimal height to fit all items in ListBox.
void insertItemAt(size_t _index, const UString &_name, Any _data=Any::Null)
Insert an item into a array at a specified position.
void removeAllItems()
Remove all items.
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 beginToItemFirst()
Move all elements so first becomes visible.
static const std::string & getClassTypeName()
Definition: MyGUI_ListBox.h:32
void setItemDataAt(size_t _index, Any _data)
Replace an item data at a specified position.
EventPair< EventHandle_WidgetSizeT, EventHandle_ListPtrSizeT > eventListSelectAccept
void removeItemAt(size_t _index)
Remove item at a specified position.
void setItemNameAt(size_t _index, const UString &_name)
Replace an item name at a specified position.
void setIndexSelected(size_t _index)
void setCoord(const IntCoord &_value) override
EventPair< EventHandle_WidgetSizeT, EventHandle_ListPtrSizeT > eventListMouseItemActivate
A UTF-16 string with implicit conversion to/from std::string and std::wstring.
const std::string & getUserString(const std::string &_key) const
widget description should be here.
Definition: MyGUI_Widget.h:37
EventHandle_WidgetStringString eventChangeProperty
Definition: MyGUI_Widget.h:267
void assignWidget(T *&_widget, const std::string &_name)
Definition: MyGUI_Widget.h:335
virtual void setVisible(bool _value)
Widget * _createSkinWidget(WidgetStyle _style, const std::string &_type, const std::string &_skin, const IntCoord &_coord, Align _align, const std::string &_layer="", const std::string &_name="")
IntSize getParentSize() const
EventHandle_WidgetWidget eventKeyLostFocus
EventHandle_WidgetIntIntButton eventMouseButtonPressed
EventHandle_WidgetToolTip eventToolTip
void setNeedToolTip(bool _value)
EventHandle_WidgetInt eventMouseWheel
const float COMBO_ALPHA_MAX
const float COMBO_ALPHA_MIN
const float ALPHA_MIN
Definition: MyGUI_Macros.h:20
delegates::DelegateFunction< Args... > * newDelegate(void(*_func)(Args... args))
types::TCoord< int > IntCoord
Definition: MyGUI_Types.h:35
const float ALPHA_MAX
Definition: MyGUI_Macros.h:19
const float COMBO_ALPHA_COEF
const size_t ITEM_NONE
Definition: MyGUI_Macros.h:17
unsigned int Char
Definition: MyGUI_Types.h:49