MyGUI  3.0.1
MyGUI_ComboBox.cpp
Go to the documentation of this file.
1 
7 /*
8  This file is part of MyGUI.
9 
10  MyGUI is free software: you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  MyGUI is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with MyGUI. If not, see <http://www.gnu.org/licenses/>.
22 */
23 #include "MyGUI_Precompiled.h"
24 #include "MyGUI_ComboBox.h"
26 #include "MyGUI_InputManager.h"
27 #include "MyGUI_WidgetManager.h"
28 #include "MyGUI_Gui.h"
29 #include "MyGUI_List.h"
30 #include "MyGUI_Button.h"
31 #include "MyGUI_ResourceSkin.h"
32 #include "MyGUI_LayerManager.h"
33 
34 namespace MyGUI
35 {
36 
37  const float COMBO_ALPHA_MAX = ALPHA_MAX;
38  const float COMBO_ALPHA_MIN = ALPHA_MIN;
39  const float COMBO_ALPHA_COEF = 4.0f;
40 
42  mButton(nullptr),
43  mList(nullptr),
44  mListShow(false),
45  mMaxHeight(0),
46  mItemIndex(ITEM_NONE),
47  mModeDrop(false),
48  mDropMouse(false),
49  mShowSmooth(false),
50  mManualList(true)
51  {
52  }
53 
54  void ComboBox::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
55  {
56  Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
57 
58  initialiseWidgetSkin(_info);
59  }
60 
62  {
63  shutdownWidgetSkin();
64  }
65 
67  {
68  shutdownWidgetSkin();
70  initialiseWidgetSkin(_info);
71  }
72 
73  void ComboBox::initialiseWidgetSkin(ResourceSkin* _info)
74  {
75  // парсим свойства
76  const MapString& properties = _info->getProperties();
77  if (!properties.empty())
78  {
79  MapString::const_iterator iter = properties.find("HeightList");
80  if (iter != properties.end()) mMaxHeight = utility::parseValue<int>(iter->second);
81 
82  iter = properties.find("ListSmoothShow");
83  if (iter != properties.end()) setSmoothShow(utility::parseBool(iter->second));
84  }
85 
86  // парсим кнопку
87  for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
88  {
89  if (*(*iter)->_getInternalData<std::string>() == "Button")
90  {
91  MYGUI_DEBUG_ASSERT( ! mButton, "widget already assigned");
92  mButton = (*iter)->castType<Button>();
93  mButton->eventMouseButtonPressed = newDelegate(this, &ComboBox::notifyButtonPressed);
94  }
95  else if (*(*iter)->_getInternalData<std::string>() == "List")
96  {
97  MYGUI_DEBUG_ASSERT( ! mList, "widget already assigned");
98  mList = (*iter)->castType<List>();
99  mList->setVisible(false);
100  mList->eventKeyLostFocus = newDelegate(this, &ComboBox::notifyListLostFocus);
101  mList->eventListSelectAccept = newDelegate(this, &ComboBox::notifyListSelectAccept);
102  mList->eventListMouseItemActivate = newDelegate(this, &ComboBox::notifyListMouseItemActivate);
103  mList->eventListChangePosition = newDelegate(this, &ComboBox::notifyListChangePosition);
104  }
105  }
106 
107  //OBSOLETE
108  //MYGUI_ASSERT(nullptr != mButton, "Child Button not found in skin (combobox must have Button)");
109 
110  //MYGUI_ASSERT(nullptr != mList, "Child List not found in skin (combobox must have List)");
111  mManualList = (mList == nullptr);
112  if (mList == nullptr)
113  {
114  std::string list_skin;
115  MapString::const_iterator iter = properties.find("ListSkin");
116  if (iter != properties.end()) list_skin = iter->second;
117  std::string list_layer;
118  iter = properties.find("ListLayer");
119  if (iter != properties.end()) list_layer = iter->second;
120  mList = createWidget<MyGUI::List>(WidgetStyle::Popup, list_skin, IntCoord(), Align::Default, list_layer);
121  mWidgetChild.pop_back();
122 
123  mList->setVisible(false);
124  mList->eventKeyLostFocus = newDelegate(this, &ComboBox::notifyListLostFocus);
125  mList->eventListSelectAccept = newDelegate(this, &ComboBox::notifyListSelectAccept);
126  mList->eventListMouseItemActivate = newDelegate(this, &ComboBox::notifyListMouseItemActivate);
127  mList->eventListChangePosition = newDelegate(this, &ComboBox::notifyListChangePosition);
128  }
129 
130  // корректируем высоту списка
131  //if (mMaxHeight < mList->getFontHeight()) mMaxHeight = mList->getFontHeight();
132 
133  // подписываем дочерние классы на скролл
134  if (mWidgetClient != nullptr)
135  {
136  mWidgetClient->eventMouseWheel = newDelegate(this, &ComboBox::notifyMouseWheel);
137  mWidgetClient->eventMouseButtonPressed = newDelegate(this, &ComboBox::notifyMousePressed);
138  }
139 
140  // подписываемся на изменения текста
141  eventEditTextChange = newDelegate(this, &ComboBox::notifyEditTextChange);
142  }
143 
144  void ComboBox::shutdownWidgetSkin()
145  {
146  if (mManualList)
147  {
148  mWidgetChild.push_back(mList);
150  }
151  mList = nullptr;
152  mButton = nullptr;
153  }
154 
155 
156  void ComboBox::notifyButtonPressed(Widget* _sender, int _left, int _top, MouseButton _id)
157  {
158  if (MouseButton::Left != _id) return;
159 
160  mDropMouse = true;
161 
162  if (mListShow) hideList();
163  else showList();
164  }
165 
166  void ComboBox::notifyListLostFocus(Widget* _sender, Widget* _new)
167  {
168  if (mDropMouse)
169  {
170  mDropMouse = false;
172  // кнопка сама уберет список
173  if (focus == mButton) return;
174  // в режиме дропа все окна учавствуют
175  if ( (mModeDrop) && (focus == mWidgetClient) ) return;
176  }
177 
178  hideList();
179  }
180 
181  void ComboBox::notifyListSelectAccept(List* _widget, size_t _position)
182  {
183  mItemIndex = _position;
184  Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
185 
186  mDropMouse = false;
188 
189  if (mModeDrop)
190  {
192  eventComboAccept.m_event(this, mItemIndex);
193  }
194  }
195 
196  void ComboBox::notifyListChangePosition(List* _widget, size_t _position)
197  {
198  mItemIndex = _position;
199  eventComboChangePosition(this, _position);
200  }
201 
203  {
204  Base::onKeyButtonPressed(_key, _char);
205 
206  // при нажатии вниз, показываем лист
207  if (_key == KeyCode::ArrowDown)
208  {
209  // выкидываем список только если мыша свободна
210  if (!InputManager::getInstance().isCaptureMouse())
211  {
212  showList();
213  }
214  }
215  // нажат ввод в окне редиктирования
216  else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
217  {
219  eventComboAccept.m_event(this, mItemIndex);
220  }
221 
222  }
223 
224  void ComboBox::notifyListMouseItemActivate(List* _widget, size_t _position)
225  {
226  mItemIndex = _position;
227  Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
228 
230 
231  if (mModeDrop)
232  {
234  eventComboAccept.m_event(this, mItemIndex);
235  }
236  }
237 
238  void ComboBox::notifyMouseWheel(Widget* _sender, int _rel)
239  {
240  if (mList->getItemCount() == 0) return;
241  if (InputManager::getInstance().getKeyFocusWidget() != this) return;
243 
244  if (_rel > 0)
245  {
246  if (mItemIndex != 0)
247  {
248  if (mItemIndex == ITEM_NONE) mItemIndex = 0;
249  else mItemIndex --;
250  Base::setCaption(mList->getItemNameAt(mItemIndex));
251  mList->setIndexSelected(mItemIndex);
252  mList->beginToItemAt(mItemIndex);
253  eventComboChangePosition(this, mItemIndex);
254  }
255  }
256  else if (_rel < 0)
257  {
258  if ((mItemIndex+1) < mList->getItemCount())
259  {
260  if (mItemIndex == ITEM_NONE) mItemIndex = 0;
261  else mItemIndex ++;
262  Base::setCaption(mList->getItemNameAt(mItemIndex));
263  mList->setIndexSelected(mItemIndex);
264  mList->beginToItemAt(mItemIndex);
265  eventComboChangePosition(this, mItemIndex);
266  }
267  }
268  }
269 
270  void ComboBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
271  {
272  // обязательно отдаем отцу, а то мы у него в наглую отняли
273  Base::notifyMousePressed(_sender, _left, _top, _id);
274 
275  mDropMouse = true;
276 
277  // показываем список
278  if (mModeDrop) notifyButtonPressed(nullptr, _left, _top, _id);
279  }
280 
281  void ComboBox::notifyEditTextChange(Edit* _sender)
282  {
283  // сбрасываем выделенный элемент
284  if (ITEM_NONE != mItemIndex)
285  {
286  mItemIndex = ITEM_NONE;
287  mList->setIndexSelected(mItemIndex);
288  mList->beginToItemFirst();
289  eventComboChangePosition(this, mItemIndex);
290  }
291  }
292 
293  void ComboBox::showList()
294  {
295  // пустой список не показываем
296  if (mList->getItemCount() == 0) return;
297 
298  mListShow = true;
299 
300  int height = mList->getOptimalHeight();
301  if (height > mMaxHeight) height = mMaxHeight;
302 
303  // берем глобальные координаты выджета
304  IntCoord coord = this->getAbsoluteCoord();
305 
306  //показываем список вверх
307  if ((coord.top + coord.height + height) > Gui::getInstance().getViewSize().height)
308  {
309  coord.height = height;
310  coord.top -= coord.height;
311  }
312  // показываем список вниз
313  else
314  {
315  coord.top += coord.height;
316  coord.height = height;
317  }
318  mList->setCoord(coord);
319 
320  if (mShowSmooth)
321  {
322  ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MAX, COMBO_ALPHA_COEF, true);
323  ControllerManager::getInstance().addItem(mList, controller);
324  }
325  else
326  {
327  mList->setVisible(true);
328  }
329 
331  }
332 
333  void ComboBox::actionWidgetHide(Widget* _widget)
334  {
335  _widget->setVisible(false);
336  _widget->setEnabled(true);
337  }
338 
339  void ComboBox::hideList()
340  {
341  mListShow = false;
342 
343  if (mShowSmooth)
344  {
345  ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MIN, COMBO_ALPHA_COEF, false);
346  controller->eventPostAction = newDelegate(this, &ComboBox::actionWidgetHide);
347  ControllerManager::getInstance().addItem(mList, controller);
348  }
349  else
350  {
351  mList->setVisible(false);
352  }
353  }
354 
355  void ComboBox::setIndexSelected(size_t _index)
356  {
357  MYGUI_ASSERT_RANGE_AND_NONE(_index, mList->getItemCount(), "ComboBox::setIndexSelected");
358  mItemIndex = _index;
359  mList->setIndexSelected(_index);
360  if (_index == ITEM_NONE)
361  {
362  Base::setCaption("");
363  return;
364  }
365  Base::setCaption(mList->getItemNameAt(_index));
366  Base::updateView(); // hook for update
367  }
368 
369  void ComboBox::setItemNameAt(size_t _index, const UString& _name)
370  {
371  mList->setItemNameAt(_index, _name);
372  mItemIndex = ITEM_NONE;//FIXME
373  mList->setIndexSelected(mItemIndex);//FIXME
374  }
375 
376  void ComboBox::setItemDataAt(size_t _index, Any _data)
377  {
378  mList->setItemDataAt(_index, _data);
379  mItemIndex = ITEM_NONE;//FIXME
380  mList->setIndexSelected(mItemIndex);//FIXME
381  }
382 
383  void ComboBox::insertItemAt(size_t _index, const UString& _item, Any _data)
384  {
385  mList->insertItemAt(_index, _item, _data);
386  mItemIndex = ITEM_NONE;//FIXME
387  mList->setIndexSelected(mItemIndex);//FIXME
388  }
389 
390  void ComboBox::removeItemAt(size_t _index)
391  {
392  mList->removeItemAt(_index);
393  mItemIndex = ITEM_NONE;//FIXME
394  mList->clearIndexSelected();//FIXME
395  }
396 
398  {
399  mItemIndex = ITEM_NONE;//FIXME
400  mList->removeAllItems();//FIXME заново созданные строки криво стоят
401  }
402 
403  void ComboBox::setComboModeDrop(bool _drop)
404  {
405  mModeDrop = _drop;
406  setEditStatic(mModeDrop);
407  }
408 
409  ControllerFadeAlpha* ComboBox::createControllerFadeAlpha(float _alpha, float _coef, bool _enable)
410  {
412  ControllerFadeAlpha* controller = item->castType<ControllerFadeAlpha>();
413 
414  controller->setAlpha(_alpha);
415  controller->setCoef(_coef);
416  controller->setEnabled(_enable);
417 
418  return controller;
419  }
420 
422  {
423  return mList->findItemIndexWith(_name);
424  }
425 
426  void ComboBox::setProperty(const std::string& _key, const std::string& _value)
427  {
428  if (_key == "ComboBox_ModeDrop") setComboModeDrop(utility::parseValue<bool>(_value));
429  else if (_key == "ComboBox_AddItem") addItem(_value);
430  else
431  {
432  Base::setProperty(_key, _value);
433  return;
434  }
435  eventChangeProperty(this, _key, _value);
436  }
437 
438 } // namespace MyGUI