MyGUI  3.2.1
MyGUI_ComboBox.cpp
Go to the documentation of this file.
00001 /*
00002  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
00003  * Distributed under the MIT License
00004  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
00005  */
00006 
00007 #include "MyGUI_Precompiled.h"
00008 #include "MyGUI_ComboBox.h"
00009 #include "MyGUI_ControllerManager.h"
00010 #include "MyGUI_InputManager.h"
00011 #include "MyGUI_WidgetManager.h"
00012 #include "MyGUI_Gui.h"
00013 #include "MyGUI_ListBox.h"
00014 #include "MyGUI_Button.h"
00015 #include "MyGUI_ResourceSkin.h"
00016 #include "MyGUI_LayerManager.h"
00017 
00018 namespace MyGUI
00019 {
00020 
00021     const float COMBO_ALPHA_MAX  = ALPHA_MAX;
00022     const float COMBO_ALPHA_MIN  = ALPHA_MIN;
00023     const float COMBO_ALPHA_COEF = 4.0f;
00024 
00025     ComboBox::ComboBox() :
00026         mButton(nullptr),
00027         mList(nullptr),
00028         mListShow(false),
00029         mMaxListLength(-1),
00030         mItemIndex(ITEM_NONE),
00031         mModeDrop(false),
00032         mDropMouse(false),
00033         mShowSmooth(false),
00034         mFlowDirection(FlowDirection::TopToBottom)
00035     {
00036     }
00037 
00038     void ComboBox::initialiseOverride()
00039     {
00040         Base::initialiseOverride();
00041 
00043         assignWidget(mButton, "Button");
00044         if (mButton != nullptr)
00045         {
00046             mButton->eventMouseButtonPressed += newDelegate(this, &ComboBox::notifyButtonPressed);
00047         }
00048 
00050         assignWidget(mList, "List");
00051 
00052         if (mList == nullptr)
00053         {
00054             std::string list_skin = getUserString("ListSkin");
00055             std::string list_layer = getUserString("ListLayer");
00056 
00057             mList = static_cast<ListBox*>(_createSkinWidget(WidgetStyle::Popup, ListBox::getClassTypeName(), list_skin, IntCoord(), Align::Default, list_layer));
00058         }
00059 
00060         if (mList != nullptr)
00061         {
00062             mList->setActivateOnClick(true);
00063 
00064             mList->setVisible(false);
00065             mList->eventKeyLostFocus += newDelegate(this, &ComboBox::notifyListLostFocus);
00066             mList->eventListSelectAccept += newDelegate(this, &ComboBox::notifyListSelectAccept);
00067             mList->eventListMouseItemActivate += newDelegate(this, &ComboBox::notifyListMouseItemActivate);
00068             mList->eventListChangePosition += newDelegate(this, &ComboBox::notifyListChangePosition);
00069 
00070             mList->setNeedToolTip(true);
00071             mList->eventToolTip += newDelegate(this, &ComboBox::notifyToolTip);
00072         }
00073 
00074         // подписываем дочерние классы на скролл
00075         if (mClient != nullptr)
00076         {
00077             mClient->eventMouseWheel += newDelegate(this, &ComboBox::notifyMouseWheel);
00078             mClient->eventMouseButtonPressed += newDelegate(this, &ComboBox::notifyMousePressed);
00079 
00080             mClient->setNeedToolTip(true);
00081             mClient->eventToolTip += newDelegate(this, &ComboBox::notifyToolTip);
00082         }
00083 
00084         // подписываемся на изменения текста
00085         eventEditTextChange += newDelegate(this, &ComboBox::notifyEditTextChange);
00086     }
00087 
00088     void ComboBox::shutdownOverride()
00089     {
00090         mList = nullptr;
00091         mButton = nullptr;
00092         mClient = nullptr;
00093 
00094         Base::shutdownOverride();
00095     }
00096 
00097     void ComboBox::notifyButtonPressed(Widget* _sender, int _left, int _top, MouseButton _id)
00098     {
00099         if (MouseButton::Left != _id)
00100             return;
00101 
00102         mDropMouse = true;
00103 
00104         if (mListShow)
00105             hideList();
00106         else
00107             showList();
00108     }
00109 
00110     void ComboBox::notifyListLostFocus(Widget* _sender, Widget* _new)
00111     {
00112         if (mDropMouse)
00113         {
00114             mDropMouse = false;
00115             Widget* focus = InputManager::getInstance().getMouseFocusWidget();
00116 
00117             // кнопка сама уберет список
00118             if (focus == mButton)
00119                 return;
00120 
00121             // в режиме дропа все окна учавствуют
00122             if (mModeDrop && focus == mClient)
00123                 return;
00124         }
00125 
00126         hideList();
00127     }
00128 
00129     void ComboBox::notifyListSelectAccept(ListBox* _widget, size_t _position)
00130     {
00131         mItemIndex = _position;
00132         Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
00133 
00134         mDropMouse = false;
00135         InputManager::getInstance().setKeyFocusWidget(this);
00136 
00137         if (mModeDrop)
00138         {
00139             _resetContainer(false);
00140 
00141             eventComboAccept.m_eventObsolete(this);
00142             eventComboAccept.m_event(this, mItemIndex);
00143         }
00144     }
00145 
00146     void ComboBox::notifyListChangePosition(ListBox* _widget, size_t _position)
00147     {
00148         mItemIndex = _position;
00149 
00150         _resetContainer(false);
00151 
00152         eventComboChangePosition(this, _position);
00153     }
00154 
00155     void ComboBox::onKeyButtonPressed(KeyCode _key, Char _char)
00156     {
00157         Base::onKeyButtonPressed(_key, _char);
00158 
00159         // при нажатии вниз, показываем лист
00160         if (_key == KeyCode::ArrowDown)
00161         {
00162             // выкидываем список только если мыша свободна
00163             if (!InputManager::getInstance().isCaptureMouse())
00164             {
00165                 showList();
00166             }
00167         }
00168         // нажат ввод в окне редиктирования
00169         else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
00170         {
00171             _resetContainer(false);
00172 
00173             eventComboAccept.m_eventObsolete(this);
00174             eventComboAccept.m_event(this, mItemIndex);
00175         }
00176     }
00177 
00178     void ComboBox::notifyListMouseItemActivate(ListBox* _widget, size_t _position)
00179     {
00180         mItemIndex = _position;
00181         Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
00182 
00183         InputManager::getInstance().setKeyFocusWidget(this);
00184 
00185         if (mModeDrop)
00186         {
00187             _resetContainer(false);
00188 
00189             eventComboAccept.m_eventObsolete(this);
00190             eventComboAccept.m_event(this, mItemIndex);
00191         }
00192     }
00193 
00194     void ComboBox::notifyMouseWheel(Widget* _sender, int _rel)
00195     {
00196         if (mList->getItemCount() == 0)
00197             return;
00198         if (InputManager::getInstance().getKeyFocusWidget() != this)
00199             return;
00200         if (InputManager::getInstance().isCaptureMouse())
00201             return;
00202 
00203         if (_rel > 0)
00204         {
00205             if (mItemIndex != 0)
00206             {
00207                 if (mItemIndex == ITEM_NONE)
00208                     mItemIndex = 0;
00209                 else
00210                     mItemIndex --;
00211                 Base::setCaption(mList->getItemNameAt(mItemIndex));
00212                 mList->setIndexSelected(mItemIndex);
00213                 mList->beginToItemAt(mItemIndex);
00214 
00215                 _resetContainer(false);
00216 
00217                 eventComboChangePosition(this, mItemIndex);
00218             }
00219         }
00220         else if (_rel < 0)
00221         {
00222             if ((mItemIndex + 1) < mList->getItemCount())
00223             {
00224                 if (mItemIndex == ITEM_NONE)
00225                     mItemIndex = 0;
00226                 else
00227                     mItemIndex ++;
00228                 Base::setCaption(mList->getItemNameAt(mItemIndex));
00229                 mList->setIndexSelected(mItemIndex);
00230                 mList->beginToItemAt(mItemIndex);
00231 
00232                 _resetContainer(false);
00233 
00234                 eventComboChangePosition(this, mItemIndex);
00235             }
00236         }
00237     }
00238 
00239     void ComboBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
00240     {
00241         // обязательно отдаем отцу, а то мы у него в наглую отняли
00242         Base::notifyMousePressed(_sender, _left, _top, _id);
00243 
00244         mDropMouse = true;
00245 
00246         // показываем список
00247         if (mModeDrop)
00248             notifyButtonPressed(nullptr, _left, _top, _id);
00249     }
00250 
00251     void ComboBox::notifyEditTextChange(EditBox* _sender)
00252     {
00253         // сбрасываем выделенный элемент
00254         if (ITEM_NONE != mItemIndex)
00255         {
00256             mItemIndex = ITEM_NONE;
00257             mList->setIndexSelected(mItemIndex);
00258             mList->beginToItemFirst();
00259 
00260             _resetContainer(false);
00261 
00262             eventComboChangePosition(this, mItemIndex);
00263         }
00264     }
00265 
00266     void ComboBox::showList()
00267     {
00268         // пустой список не показываем
00269         if (mList->getItemCount() == 0)
00270             return;
00271 
00272         mListShow = true;
00273 
00274         IntCoord coord = calculateListPosition();
00275         mList->setCoord(coord);
00276 
00277         if (mShowSmooth)
00278         {
00279             ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MAX, COMBO_ALPHA_COEF, true);
00280             ControllerManager::getInstance().addItem(mList, controller);
00281         }
00282         else
00283         {
00284             mList->setVisible(true);
00285         }
00286 
00287         InputManager::getInstance().setKeyFocusWidget(mList);
00288     }
00289 
00290     void ComboBox::actionWidgetHide(Widget* _widget, ControllerItem* _controller)
00291     {
00292         _widget->setVisible(false);
00293         _widget->setEnabled(true);
00294     }
00295 
00296     void ComboBox::hideList()
00297     {
00298         mListShow = false;
00299 
00300         if (mShowSmooth)
00301         {
00302             ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MIN, COMBO_ALPHA_COEF, false);
00303             controller->eventPostAction += newDelegate(this, &ComboBox::actionWidgetHide);
00304             ControllerManager::getInstance().addItem(mList, controller);
00305         }
00306         else
00307         {
00308             mList->setVisible(false);
00309         }
00310     }
00311 
00312     void ComboBox::setIndexSelected(size_t _index)
00313     {
00314         MYGUI_ASSERT_RANGE_AND_NONE(_index, mList->getItemCount(), "ComboBox::setIndexSelected");
00315         mItemIndex = _index;
00316         mList->setIndexSelected(_index);
00317         if (_index == ITEM_NONE)
00318         {
00319             Base::setCaption("");
00320             return;
00321         }
00322         Base::setCaption(mList->getItemNameAt(_index));
00323         Base::updateView(); // hook for update
00324     }
00325 
00326     void ComboBox::setItemNameAt(size_t _index, const UString& _name)
00327     {
00328         mList->setItemNameAt(_index, _name);
00329         mItemIndex = ITEM_NONE;//FIXME
00330         mList->setIndexSelected(mItemIndex);//FIXME
00331     }
00332 
00333     void ComboBox::setItemDataAt(size_t _index, Any _data)
00334     {
00335         mList->setItemDataAt(_index, _data);
00336         mItemIndex = ITEM_NONE;//FIXME
00337         mList->setIndexSelected(mItemIndex);//FIXME
00338     }
00339 
00340     void ComboBox::insertItemAt(size_t _index, const UString& _item, Any _data)
00341     {
00342         mList->insertItemAt(_index, _item, _data);
00343         mItemIndex = ITEM_NONE;//FIXME
00344         mList->setIndexSelected(mItemIndex);//FIXME
00345     }
00346 
00347     void ComboBox::removeItemAt(size_t _index)
00348     {
00349         mList->removeItemAt(_index);
00350         mItemIndex = ITEM_NONE;//FIXME
00351         mList->clearIndexSelected();//FIXME
00352     }
00353 
00354     void ComboBox::removeAllItems()
00355     {
00356         mItemIndex = ITEM_NONE;//FIXME
00357         mList->removeAllItems();//FIXME заново созданные строки криво стоят
00358     }
00359 
00360     void ComboBox::setComboModeDrop(bool _drop)
00361     {
00362         mModeDrop = _drop;
00363         setEditStatic(mModeDrop);
00364     }
00365 
00366     ControllerFadeAlpha* ComboBox::createControllerFadeAlpha(float _alpha, float _coef, bool _enable)
00367     {
00368         ControllerItem* item = ControllerManager::getInstance().createItem(ControllerFadeAlpha::getClassTypeName());
00369         ControllerFadeAlpha* controller = item->castType<ControllerFadeAlpha>();
00370 
00371         controller->setAlpha(_alpha);
00372         controller->setCoef(_coef);
00373         controller->setEnabled(_enable);
00374 
00375         return controller;
00376     }
00377 
00378     size_t ComboBox::findItemIndexWith(const UString& _name)
00379     {
00380         return mList->findItemIndexWith(_name);
00381     }
00382 
00383     void ComboBox::setFlowDirection(FlowDirection _value)
00384     {
00385         mFlowDirection = _value;
00386     }
00387 
00388     IntCoord ComboBox::calculateListPosition()
00389     {
00390         int length = 0;
00391         if (mFlowDirection.isVertical())
00392             length = mList->getOptimalHeight();
00393         else
00394             length = mMaxListLength;
00395 
00396         if (mMaxListLength > 0 && length > mMaxListLength)
00397             length = mMaxListLength;
00398 
00399         // берем глобальные координаты выджета
00400         IntCoord coord = getAbsoluteCoord();
00401         // размер леера
00402         IntSize sizeView = mList->getParentSize();
00403 
00404         if (mFlowDirection == FlowDirection::TopToBottom)
00405         {
00406             if ((coord.bottom() + length) <= sizeView.height)
00407                 coord.top += coord.height;
00408             else
00409                 coord.top -= length;
00410             coord.height = length;
00411         }
00412         else if (mFlowDirection == FlowDirection::BottomToTop)
00413         {
00414             if ((coord.top - length) >= 0)
00415                 coord.top -= length;
00416             else
00417                 coord.top += coord.height;
00418             coord.height = length;
00419         }
00420         else if (mFlowDirection == FlowDirection::LeftToRight)
00421         {
00422             if ((coord.right() + length) <= sizeView.width)
00423                 coord.left += coord.width;
00424             else
00425                 coord.left -= length;
00426             coord.width = length;
00427         }
00428         else if (mFlowDirection == FlowDirection::RightToLeft)
00429         {
00430             if ((coord.left - length) >= 0)
00431                 coord.left -= length;
00432             else
00433                 coord.left += coord.width;
00434             coord.width = length;
00435         }
00436 
00437         return coord;
00438     }
00439 
00440     void ComboBox::setPropertyOverride(const std::string& _key, const std::string& _value)
00441     {
00443         if (_key == "ModeDrop")
00444             setComboModeDrop(utility::parseValue<bool>(_value));
00445 
00447         else if (_key == "FlowDirection")
00448             setFlowDirection(utility::parseValue<FlowDirection>(_value));
00449 
00451         else if (_key == "MaxListLength")
00452             setMaxListLength(utility::parseValue<int>(_value));
00453 
00455         else if (_key == "SmoothShow")
00456             setSmoothShow(utility::parseValue<bool>(_value));
00457 
00458         // не коментировать
00459         else if (_key == "AddItem")
00460             addItem(_value);
00461 
00462         else
00463         {
00464             Base::setPropertyOverride(_key, _value);
00465             return;
00466         }
00467 
00468         eventChangeProperty(this, _key, _value);
00469     }
00470 
00471     size_t ComboBox::getItemCount() const
00472     {
00473         return mList->getItemCount();
00474     }
00475 
00476     void ComboBox::addItem(const UString& _name, Any _data)
00477     {
00478         return insertItemAt(ITEM_NONE, _name, _data);
00479     }
00480 
00481     size_t ComboBox::getIndexSelected() const
00482     {
00483         return mItemIndex;
00484     }
00485 
00486     void ComboBox::clearIndexSelected()
00487     {
00488         setIndexSelected(ITEM_NONE);
00489     }
00490 
00491     void ComboBox::clearItemDataAt(size_t _index)
00492     {
00493         setItemDataAt(_index, Any::Null);
00494     }
00495 
00496     const UString& ComboBox::getItemNameAt(size_t _index)
00497     {
00498         return mList->getItemNameAt(_index);
00499     }
00500 
00501     void ComboBox::beginToItemAt(size_t _index)
00502     {
00503         mList->beginToItemAt(_index);
00504     }
00505 
00506     void ComboBox::beginToItemFirst()
00507     {
00508         if (getItemCount())
00509             beginToItemAt(0);
00510     }
00511 
00512     void ComboBox::beginToItemLast()
00513     {
00514         if (getItemCount())
00515             beginToItemAt(getItemCount() - 1);
00516     }
00517 
00518     void ComboBox::beginToItemSelected()
00519     {
00520         if (getIndexSelected() != ITEM_NONE)
00521             beginToItemAt(getIndexSelected());
00522     }
00523 
00524     bool ComboBox::getComboModeDrop() const
00525     {
00526         return mModeDrop;
00527     }
00528 
00529     void ComboBox::setSmoothShow(bool _value)
00530     {
00531         mShowSmooth = _value;
00532     }
00533 
00534     bool ComboBox::getSmoothShow() const
00535     {
00536         return mShowSmooth;
00537     }
00538 
00539     void ComboBox::setMaxListLength(int _value)
00540     {
00541         mMaxListLength = _value;
00542     }
00543 
00544     int ComboBox::getMaxListLength() const
00545     {
00546         return mMaxListLength;
00547     }
00548 
00549     FlowDirection ComboBox::getFlowDirection() const
00550     {
00551         return mFlowDirection;
00552     }
00553 
00554     void ComboBox::notifyToolTip(Widget* _sender, const ToolTipInfo& _info)
00555     {
00556         if (getNeedToolTip())
00557             eventToolTip(this, _info);
00558     }
00559 
00560     size_t ComboBox::_getItemCount()
00561     {
00562         return getItemCount();
00563     }
00564 
00565     void ComboBox::_addItem(const MyGUI::UString& _name)
00566     {
00567         addItem(_name);
00568     }
00569 
00570     void ComboBox::_removeItemAt(size_t _index)
00571     {
00572         removeItemAt(_index);
00573     }
00574 
00575     void ComboBox::_setItemNameAt(size_t _index, const UString& _name)
00576     {
00577         setItemNameAt(_index, _name);
00578     }
00579 
00580     const UString& ComboBox::_getItemNameAt(size_t _index)
00581     {
00582         return getItemNameAt(_index);
00583     }
00584 
00585     void ComboBox::_resetContainer(bool _update)
00586     {
00587         Base::_resetContainer(_update);
00588         if (mList != nullptr)
00589             mList->_resetContainer(_update);
00590     }
00591 
00592 } // namespace MyGUI