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