MyGUI  3.2.0
MyGUI_ComboBox.cpp
Go to the documentation of this file.
00001 
00006 /*
00007     This file is part of MyGUI.
00008 
00009     MyGUI is free software: you can redistribute it and/or modify
00010     it under the terms of the GNU Lesser General Public License as published by
00011     the Free Software Foundation, either version 3 of the License, or
00012     (at your option) any later version.
00013 
00014     MyGUI is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     along with MyGUI.  If not, see <http://www.gnu.org/licenses/>.
00021 */
00022 #include "MyGUI_Precompiled.h"
00023 #include "MyGUI_ComboBox.h"
00024 #include "MyGUI_ControllerManager.h"
00025 #include "MyGUI_InputManager.h"
00026 #include "MyGUI_WidgetManager.h"
00027 #include "MyGUI_Gui.h"
00028 #include "MyGUI_ListBox.h"
00029 #include "MyGUI_Button.h"
00030 #include "MyGUI_ResourceSkin.h"
00031 #include "MyGUI_LayerManager.h"
00032 
00033 namespace MyGUI
00034 {
00035 
00036     const float COMBO_ALPHA_MAX  = ALPHA_MAX;
00037     const float COMBO_ALPHA_MIN  = ALPHA_MIN;
00038     const float COMBO_ALPHA_COEF = 4.0f;
00039 
00040     ComboBox::ComboBox() :
00041         mButton(nullptr),
00042         mList(nullptr),
00043         mListShow(false),
00044         mMaxListLength(-1),
00045         mItemIndex(ITEM_NONE),
00046         mModeDrop(false),
00047         mDropMouse(false),
00048         mShowSmooth(false),
00049         mFlowDirection(FlowDirection::TopToBottom)
00050     {
00051     }
00052 
00053     void ComboBox::initialiseOverride()
00054     {
00055         Base::initialiseOverride();
00056 
00057         assignWidget(mButton, "Button");
00058         if (mButton != nullptr)
00059         {
00060             mButton->eventMouseButtonPressed += newDelegate(this, &ComboBox::notifyButtonPressed);
00061         }
00062 
00063         assignWidget(mList, "List");
00064 
00065         if (mList == nullptr)
00066         {
00067             std::string list_skin = getUserString("ListSkin");
00068             std::string list_layer = getUserString("ListLayer");
00069 
00070             mList = static_cast<ListBox*>(_createSkinWidget(WidgetStyle::Popup, ListBox::getClassTypeName(), list_skin, IntCoord(), Align::Default, list_layer));
00071         }
00072 
00073         if (mList != nullptr)
00074         {
00075             mList->setVisible(false);
00076             mList->eventKeyLostFocus += newDelegate(this, &ComboBox::notifyListLostFocus);
00077             mList->eventListSelectAccept += newDelegate(this, &ComboBox::notifyListSelectAccept);
00078             mList->eventListMouseItemActivate += newDelegate(this, &ComboBox::notifyListMouseItemActivate);
00079             mList->eventListChangePosition += newDelegate(this, &ComboBox::notifyListChangePosition);
00080 
00081             mList->setNeedToolTip(true);
00082             mList->eventToolTip += newDelegate(this, &ComboBox::notifyToolTip);
00083         }
00084 
00085         // подписываем дочерние классы на скролл
00086         if (mClient != nullptr)
00087         {
00088             mClient->eventMouseWheel += newDelegate(this, &ComboBox::notifyMouseWheel);
00089             mClient->eventMouseButtonPressed += newDelegate(this, &ComboBox::notifyMousePressed);
00090 
00091             mClient->setNeedToolTip(true);
00092             mClient->eventToolTip += newDelegate(this, &ComboBox::notifyToolTip);
00093         }
00094 
00095         // подписываемся на изменения текста
00096         eventEditTextChange += newDelegate(this, &ComboBox::notifyEditTextChange);
00097     }
00098 
00099     void ComboBox::shutdownOverride()
00100     {
00101         mList = nullptr;
00102         mButton = nullptr;
00103         mClient = nullptr;
00104 
00105         Base::shutdownOverride();
00106     }
00107 
00108     void ComboBox::notifyButtonPressed(Widget* _sender, int _left, int _top, MouseButton _id)
00109     {
00110         if (MouseButton::Left != _id)
00111             return;
00112 
00113         mDropMouse = true;
00114 
00115         if (mListShow)
00116             hideList();
00117         else
00118             showList();
00119     }
00120 
00121     void ComboBox::notifyListLostFocus(Widget* _sender, Widget* _new)
00122     {
00123         if (mDropMouse)
00124         {
00125             mDropMouse = false;
00126             Widget* focus = InputManager::getInstance().getMouseFocusWidget();
00127 
00128             // кнопка сама уберет список
00129             if (focus == mButton)
00130                 return;
00131 
00132             // в режиме дропа все окна учавствуют
00133             if (mModeDrop && focus == mClient)
00134                 return;
00135         }
00136 
00137         hideList();
00138     }
00139 
00140     void ComboBox::notifyListSelectAccept(ListBox* _widget, size_t _position)
00141     {
00142         mItemIndex = _position;
00143         Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
00144 
00145         mDropMouse = false;
00146         InputManager::getInstance().setKeyFocusWidget(this);
00147 
00148         if (mModeDrop)
00149         {
00150             _resetContainer(false);
00151 
00152             eventComboAccept.m_eventObsolete(this);
00153             eventComboAccept.m_event(this, mItemIndex);
00154         }
00155     }
00156 
00157     void ComboBox::notifyListChangePosition(ListBox* _widget, size_t _position)
00158     {
00159         mItemIndex = _position;
00160 
00161         _resetContainer(false);
00162 
00163         eventComboChangePosition(this, _position);
00164     }
00165 
00166     void ComboBox::onKeyButtonPressed(KeyCode _key, Char _char)
00167     {
00168         Base::onKeyButtonPressed(_key, _char);
00169 
00170         // при нажатии вниз, показываем лист
00171         if (_key == KeyCode::ArrowDown)
00172         {
00173             // выкидываем список только если мыша свободна
00174             if (!InputManager::getInstance().isCaptureMouse())
00175             {
00176                 showList();
00177             }
00178         }
00179         // нажат ввод в окне редиктирования
00180         else if ((_key == KeyCode::Return) || (_key == KeyCode::NumpadEnter))
00181         {
00182             _resetContainer(false);
00183 
00184             eventComboAccept.m_eventObsolete(this);
00185             eventComboAccept.m_event(this, mItemIndex);
00186         }
00187     }
00188 
00189     void ComboBox::notifyListMouseItemActivate(ListBox* _widget, size_t _position)
00190     {
00191         mItemIndex = _position;
00192         Base::setCaption(mItemIndex != ITEM_NONE ? mList->getItemNameAt(mItemIndex) : "");
00193 
00194         InputManager::getInstance().setKeyFocusWidget(this);
00195 
00196         if (mModeDrop)
00197         {
00198             _resetContainer(false);
00199 
00200             eventComboAccept.m_eventObsolete(this);
00201             eventComboAccept.m_event(this, mItemIndex);
00202         }
00203     }
00204 
00205     void ComboBox::notifyMouseWheel(Widget* _sender, int _rel)
00206     {
00207         if (mList->getItemCount() == 0)
00208             return;
00209         if (InputManager::getInstance().getKeyFocusWidget() != this)
00210             return;
00211         if (InputManager::getInstance().isCaptureMouse())
00212             return;
00213 
00214         if (_rel > 0)
00215         {
00216             if (mItemIndex != 0)
00217             {
00218                 if (mItemIndex == ITEM_NONE)
00219                     mItemIndex = 0;
00220                 else
00221                     mItemIndex --;
00222                 Base::setCaption(mList->getItemNameAt(mItemIndex));
00223                 mList->setIndexSelected(mItemIndex);
00224                 mList->beginToItemAt(mItemIndex);
00225 
00226                 _resetContainer(false);
00227 
00228                 eventComboChangePosition(this, mItemIndex);
00229             }
00230         }
00231         else if (_rel < 0)
00232         {
00233             if ((mItemIndex + 1) < mList->getItemCount())
00234             {
00235                 if (mItemIndex == ITEM_NONE)
00236                     mItemIndex = 0;
00237                 else
00238                     mItemIndex ++;
00239                 Base::setCaption(mList->getItemNameAt(mItemIndex));
00240                 mList->setIndexSelected(mItemIndex);
00241                 mList->beginToItemAt(mItemIndex);
00242 
00243                 _resetContainer(false);
00244 
00245                 eventComboChangePosition(this, mItemIndex);
00246             }
00247         }
00248     }
00249 
00250     void ComboBox::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
00251     {
00252         // обязательно отдаем отцу, а то мы у него в наглую отняли
00253         Base::notifyMousePressed(_sender, _left, _top, _id);
00254 
00255         mDropMouse = true;
00256 
00257         // показываем список
00258         if (mModeDrop)
00259             notifyButtonPressed(nullptr, _left, _top, _id);
00260     }
00261 
00262     void ComboBox::notifyEditTextChange(EditBox* _sender)
00263     {
00264         // сбрасываем выделенный элемент
00265         if (ITEM_NONE != mItemIndex)
00266         {
00267             mItemIndex = ITEM_NONE;
00268             mList->setIndexSelected(mItemIndex);
00269             mList->beginToItemFirst();
00270 
00271             _resetContainer(false);
00272 
00273             eventComboChangePosition(this, mItemIndex);
00274         }
00275     }
00276 
00277     void ComboBox::showList()
00278     {
00279         // пустой список не показываем
00280         if (mList->getItemCount() == 0)
00281             return;
00282 
00283         mListShow = true;
00284 
00285         IntCoord coord = calculateListPosition();
00286         mList->setCoord(coord);
00287 
00288         if (mShowSmooth)
00289         {
00290             ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MAX, COMBO_ALPHA_COEF, true);
00291             ControllerManager::getInstance().addItem(mList, controller);
00292         }
00293         else
00294         {
00295             mList->setVisible(true);
00296         }
00297 
00298         InputManager::getInstance().setKeyFocusWidget(mList);
00299     }
00300 
00301     void ComboBox::actionWidgetHide(Widget* _widget)
00302     {
00303         _widget->setVisible(false);
00304         _widget->setEnabled(true);
00305     }
00306 
00307     void ComboBox::hideList()
00308     {
00309         mListShow = false;
00310 
00311         if (mShowSmooth)
00312         {
00313             ControllerFadeAlpha* controller = createControllerFadeAlpha(COMBO_ALPHA_MIN, COMBO_ALPHA_COEF, false);
00314             controller->eventPostAction += newDelegate(this, &ComboBox::actionWidgetHide);
00315             ControllerManager::getInstance().addItem(mList, controller);
00316         }
00317         else
00318         {
00319             mList->setVisible(false);
00320         }
00321     }
00322 
00323     void ComboBox::setIndexSelected(size_t _index)
00324     {
00325         MYGUI_ASSERT_RANGE_AND_NONE(_index, mList->getItemCount(), "ComboBox::setIndexSelected");
00326         mItemIndex = _index;
00327         mList->setIndexSelected(_index);
00328         if (_index == ITEM_NONE)
00329         {
00330             Base::setCaption("");
00331             return;
00332         }
00333         Base::setCaption(mList->getItemNameAt(_index));
00334         Base::updateView(); // hook for update
00335     }
00336 
00337     void ComboBox::setItemNameAt(size_t _index, const UString& _name)
00338     {
00339         mList->setItemNameAt(_index, _name);
00340         mItemIndex = ITEM_NONE;//FIXME
00341         mList->setIndexSelected(mItemIndex);//FIXME
00342     }
00343 
00344     void ComboBox::setItemDataAt(size_t _index, Any _data)
00345     {
00346         mList->setItemDataAt(_index, _data);
00347         mItemIndex = ITEM_NONE;//FIXME
00348         mList->setIndexSelected(mItemIndex);//FIXME
00349     }
00350 
00351     void ComboBox::insertItemAt(size_t _index, const UString& _item, Any _data)
00352     {
00353         mList->insertItemAt(_index, _item, _data);
00354         mItemIndex = ITEM_NONE;//FIXME
00355         mList->setIndexSelected(mItemIndex);//FIXME
00356     }
00357 
00358     void ComboBox::removeItemAt(size_t _index)
00359     {
00360         mList->removeItemAt(_index);
00361         mItemIndex = ITEM_NONE;//FIXME
00362         mList->clearIndexSelected();//FIXME
00363     }
00364 
00365     void ComboBox::removeAllItems()
00366     {
00367         mItemIndex = ITEM_NONE;//FIXME
00368         mList->removeAllItems();//FIXME заново созданные строки криво стоят
00369     }
00370 
00371     void ComboBox::setComboModeDrop(bool _drop)
00372     {
00373         mModeDrop = _drop;
00374         setEditStatic(mModeDrop);
00375     }
00376 
00377     ControllerFadeAlpha* ComboBox::createControllerFadeAlpha(float _alpha, float _coef, bool _enable)
00378     {
00379         ControllerItem* item = ControllerManager::getInstance().createItem(ControllerFadeAlpha::getClassTypeName());
00380         ControllerFadeAlpha* controller = item->castType<ControllerFadeAlpha>();
00381 
00382         controller->setAlpha(_alpha);
00383         controller->setCoef(_coef);
00384         controller->setEnabled(_enable);
00385 
00386         return controller;
00387     }
00388 
00389     size_t ComboBox::findItemIndexWith(const UString& _name)
00390     {
00391         return mList->findItemIndexWith(_name);
00392     }
00393 
00394     void ComboBox::setFlowDirection(FlowDirection _value)
00395     {
00396         mFlowDirection = _value;
00397     }
00398 
00399     IntCoord ComboBox::calculateListPosition()
00400     {
00401         int length = 0;
00402         if (mFlowDirection.isVertical())
00403             length = mList->getOptimalHeight();
00404         else
00405             length = mMaxListLength;
00406 
00407         if (mMaxListLength > 0 && length > mMaxListLength)
00408             length = mMaxListLength;
00409 
00410         // берем глобальные координаты выджета
00411         IntCoord coord = getAbsoluteCoord();
00412         // размер леера
00413         IntSize sizeView = mList->getParentSize();
00414 
00415         if (mFlowDirection == FlowDirection::TopToBottom)
00416         {
00417             if ((coord.bottom() + length) <= sizeView.height)
00418                 coord.top += coord.height;
00419             else
00420                 coord.top -= length;
00421             coord.height = length;
00422         }
00423         else if (mFlowDirection == FlowDirection::BottomToTop)
00424         {
00425             if ((coord.top - length) >= 0)
00426                 coord.top -= length;
00427             else
00428                 coord.top += coord.height;
00429             coord.height = length;
00430         }
00431         else if (mFlowDirection == FlowDirection::LeftToRight)
00432         {
00433             if ((coord.right() + length) <= sizeView.width)
00434                 coord.left += coord.width;
00435             else
00436                 coord.left -= length;
00437             coord.width = length;
00438         }
00439         else if (mFlowDirection == FlowDirection::RightToLeft)
00440         {
00441             if ((coord.left - length) >= 0)
00442                 coord.left -= length;
00443             else
00444                 coord.left += coord.width;
00445             coord.width = length;
00446         }
00447 
00448         return coord;
00449     }
00450 
00451     void ComboBox::setPropertyOverride(const std::string& _key, const std::string& _value)
00452     {
00453         if (_key == "ModeDrop")
00454             setComboModeDrop(utility::parseValue<bool>(_value));
00455         else if (_key == "FlowDirection")
00456             setFlowDirection(utility::parseValue<FlowDirection>(_value));
00457         else if (_key == "MaxListLength")
00458             setMaxListLength(utility::parseValue<int>(_value));
00459         else if (_key == "SmoothShow")
00460             setSmoothShow(utility::parseValue<bool>(_value));
00461         else if (_key == "AddItem")
00462             addItem(_value);
00463         else
00464         {
00465             Base::setPropertyOverride(_key, _value);
00466             return;
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