// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "nel/gui/dbgroup_combo_box.h" #include "nel/gui/group_menu.h" #include "nel/misc/xml_auto_ptr.h" #include "nel/gui/ctrl_button.h" #include "nel/gui/action_handler.h" #include "nel/gui/lua_ihm.h" #include "nel/gui/widget_manager.h" #include "nel/misc/i18n.h" using namespace std; using namespace NLMISC; namespace NLGUI { NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupComboBox, std::string, "combo_box"); void force_link_dbgroup_combo_box_cpp() { } // Compare strings static inline bool lt_text(const std::pair &s1, const std::pair &s2) { return toLower(s1.second) < toLower(s2.second); } std::string CDBGroupComboBox::measureMenu; std::string CDBGroupComboBox::selectMenu; std::string CDBGroupComboBox::selectMenuOut; // *************************************************************************** CDBGroupComboBox::CDBGroupComboBox(const TCtorParam ¶m) : CInterfaceGroup(param) { _Setuped= false; _ViewText= NULL; _SelectButton= NULL; _LinkedToDB = true; _NotLinkedToDBSelection = 0; _CallingOnChangeActionHandler = false; _IsExternViewText = false; dirt(); } // *************************************************************************** CDBGroupComboBox::~CDBGroupComboBox() { } // *************************************************************************** sint32 CDBGroupComboBox::evalContentWidth() const { // get the menu to open. CGroupMenu *groupMenu= dynamic_cast(CWidgetManager::getInstance()->getElementFromId( CDBGroupComboBox::measureMenu )); if( !groupMenu ) { return 0; } fillMenu(groupMenu); groupMenu->setActive(true); groupMenu->updateCoords(); sint32 width = groupMenu->getWReal(); groupMenu->setActive(false); groupMenu->reset(); // add width for the selection arrow return width; } std::string CDBGroupComboBox::getProperty( const std::string &name ) const { if( name == "linked_to_db" ) { return toString( _LinkedToDB ); } else if( name == "value" ) { if( _Selection.getNodePtr() != NULL ) return _Selection.getNodePtr()->getFullName(); else return ""; } else return CInterfaceGroup::getProperty( name ); } void CDBGroupComboBox::setProperty( const std::string &name, const std::string &value ) { if( name == "linked_to_db" ) { bool b; if( fromString( value, b ) ) _LinkedToDB = b; return; } else if( name == "value" ) { _Selection.link( value.c_str() ); return; } else CInterfaceGroup::setProperty( name, value ); } xmlNodePtr CDBGroupComboBox::serialize( xmlNodePtr parentNode, const char *type ) const { xmlNodePtr node = CInterfaceGroup::serialize( parentNode, type ); if( node == NULL ) return NULL; xmlSetProp( node, BAD_CAST "type", BAD_CAST "combo_box" ); xmlSetProp( node, BAD_CAST "linked_to_db", BAD_CAST toString( _LinkedToDB ).c_str() ); if( _Selection.getNodePtr() != NULL ) xmlSetProp( node, BAD_CAST "value", BAD_CAST _Selection.getNodePtr()->getFullName().c_str() ); else xmlSetProp( node, BAD_CAST "value", BAD_CAST "" ); return node; } // *************************************************************************** bool CDBGroupComboBox::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup) { if( !CInterfaceGroup::parse(cur, parentGroup) ) return false; CXMLAutoPtr prop((const char*)xmlGetProp(cur, (xmlChar*)"linked_to_db")); if (prop) { _LinkedToDB = convertBool(prop); } if (_LinkedToDB) { // read the selection value CXMLAutoPtr prop((const char*)xmlGetProp(cur, (xmlChar*)"value")); if(!prop) { nlwarning("'value' not found in %s", _Id.c_str()); return false; } else { _Selection.link((const char*)prop); } } // read the sons text xmlNodePtr child; child = cur->children; while (child) { if (stricmp((char*)child->name,"combo_text") == 0) { CXMLAutoPtr name((const char*) xmlGetProp (child, (xmlChar*)"name")); if (name) { const char *propPtr = name; ucstring Text = ucstring::makeFromUtf8(propPtr); if ((strlen(propPtr)>2) && (propPtr[0] == 'u') && (propPtr[1] == 'i')) Text = CI18N::get (propPtr); addText(Text); } } child = child->next; } // optional ActionHandler on click prop= xmlGetProp(cur, (xmlChar*)"on_select_start"); if(prop) _AHOnSelectStart= (const char*)prop; // optional ActionHandler on change prop= xmlGetProp(cur, (xmlChar*)"on_change"); if(prop) _AHOnChange= (const char*)prop; prop= xmlGetProp(cur, (xmlChar*)"on_change_params"); if(prop) _AHOnChangeParams= (const char*)prop; return true; } // *************************************************************************** void CDBGroupComboBox::checkCoords () { if(!_ViewText) return; bool mustUpdate = false; if (_LinkedToDB) { // if some change in texts/selection if(_DirtySelection || _CacheSelection!=_Selection.getSInt32()) { _CacheSelection= _Selection.getSInt32(); mustUpdate = true; } } else { // if some change in texts/selection if(_DirtySelection || _CacheSelection != _NotLinkedToDBSelection) { _CacheSelection= _NotLinkedToDBSelection; mustUpdate = true; } } if (mustUpdate) { // change selected text if(_CacheSelection<0 || _CacheSelection>=(sint32)_Texts.size() ) { _ViewText->setText(ucstring()); } else if(_IsExternViewText) { _ViewText->setText(_ExternViewText); } else { _ViewText->setText(_Texts[_CacheSelection].second); } } } // *************************************************************************** void CDBGroupComboBox::updateCoords () { if(!_Setuped) setup(); CInterfaceGroup::updateCoords(); } // *************************************************************************** void CDBGroupComboBox::dirt() { _DirtySelection= true; } // *************************************************************************** void CDBGroupComboBox::resetTexts() { dirt(); _Texts.clear(); _Textures.clear(); _Grayed.clear(); } // *************************************************************************** void CDBGroupComboBox::addText(const ucstring &text) { dirt(); _Texts.push_back(make_pair((uint)_Texts.size(), text)); _Textures.push_back(std::string()); _Grayed.push_back(false); } // *************************************************************************** void CDBGroupComboBox::setText(uint i, const ucstring &text) { dirt(); if(i<_Texts.size()) _Texts[i].second= text; } // *************************************************************************** void CDBGroupComboBox::insertText(uint i, const ucstring &text) { dirt(); if(i<_Texts.size()) { addText(_Texts[_Texts.size()-1].second); for(uint t=i; t<_Texts.size()-1; t++) { _Texts[t+1] = _Texts[t]; _Textures[t+1] = _Textures[t]; _Grayed[t+1] = _Grayed[t]; } _Texts[i] = make_pair(i, text); _Textures[i] = std::string(); _Grayed[i] = false; } else if(i==_Texts.size()) addText(text); } // *************************************************************************** void CDBGroupComboBox::setTexture(uint i, const ucstring &texture) { dirt(); if(i<_Textures.size()) _Textures[i]= texture; } // *************************************************************************** void CDBGroupComboBox::setGrayed(uint i, bool g) { dirt(); if(i<_Grayed.size()) _Grayed[i] = g; } // *************************************************************************** bool CDBGroupComboBox::getGrayed(uint i) const { if(i<_Grayed.size()) return _Grayed[i]; else return false; } // *************************************************************************** void CDBGroupComboBox::removeText(uint nPos) { dirt(); if(nPos<_Texts.size()) { _Texts.erase( _Texts.begin()+nPos ); _Textures.erase( _Textures.begin()+nPos ); _Grayed.erase ( _Grayed.begin()+nPos ); } } // *************************************************************************** const ucstring &CDBGroupComboBox::getText(uint i) const { static ucstring null; if(i<_Texts.size()) return _Texts[i].second; else return null; } // *************************************************************************** uint CDBGroupComboBox::getTextId(uint i) const { static uint null = 0; if(i<_Texts.size()) return _Texts[i].first; else return null; } // *************************************************************************** uint CDBGroupComboBox::getTextPos(uint nId) const { for(uint i=0; i<_Texts.size(); i++) { if(nId == _Texts[i].first) {return i;} } return 0; } // *************************************************************************** void CDBGroupComboBox::sortText() { sort(_Texts.begin(), _Texts.end(), lt_text); } // *************************************************************************** const ucstring &CDBGroupComboBox::getTexture(uint i) const { static ucstring null; if(i<_Textures.size()) return _Textures[i]; else return null; } // *************************************************************************** void CDBGroupComboBox::setSelection(sint32 val) { _IsExternViewText = false; if (_LinkedToDB) { _Selection.setSInt32(val); } else { _NotLinkedToDBSelection = val; } if (!_AHOnChange.empty()) { if (!_CallingOnChangeActionHandler) { _CallingOnChangeActionHandler = true; CAHManager::getInstance()->runActionHandler (_AHOnChange, this, _AHOnChangeParams); _CallingOnChangeActionHandler = false; } } } // *************************************************************************** void CDBGroupComboBox::setSelectionNoTrigger(sint32 val) { if (_LinkedToDB) { _Selection.setSInt32(val); } else { _NotLinkedToDBSelection = val; } } // *************************************************************************** sint32 CDBGroupComboBox::getSelection() const { if (_LinkedToDB) { return _Selection.getSInt32(); } else { return _NotLinkedToDBSelection; } } // *************************************************************************** void CDBGroupComboBox::setSelectionText(const std::string & val) { sint32 value; for(uint i=0; isetText(_ExternViewText); } // *************************************************************************** ucstring CDBGroupComboBox::getViewText() const { return _ViewText->getText(); } // *************************************************************************** std::string CDBGroupComboBox::getSelectionText() const { ucstring text; if (_LinkedToDB) { text = getText(_Selection.getSInt32()); } else { text = getText(_NotLinkedToDBSelection); } std::string texteS; text.toString(texteS); return texteS; } // *************************************************************************** void CDBGroupComboBox::setup() { _Setuped= true; // get the viewText _ViewText= dynamic_cast(CInterfaceGroup::getView("text")); // get the button _SelectButton= dynamic_cast(CInterfaceGroup::getCtrl("select")); // force the action handler if( _SelectButton ) _SelectButton->setActionOnLeftClick("combo_box_select_start"); } // *************************************************************************** int CDBGroupComboBox::luaRemoveSelection(CLuaState &ls) { CLuaIHM::checkArgCount(ls, "removeSelection", 1); sint32 value; if(CLuaIHM::popSINT32(ls, value)) { removeText(value); } return 0; } // *************************************************************************** int CDBGroupComboBox::luaRemoveText(CLuaState &ls) { CLuaIHM::checkArgCount(ls, "removeText", 1); CLuaIHM::checkArgType(ls, "removeText", 1, LUA_TSTRING); std::string text = ls.toString(1); sint32 value; for(uint i=0; ireset(); for(uint i=0; iaddLine(getText(i), "combo_box_select_end", toString(i), "", std::string(), getTexture(i).toString(), checkable); groupMenu->setGrayedLine(i, getGrayed(i)); } } // *************************************************************************** class CHandlerComboBoxSelectStart : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const std::string &/* Params */) { CDBGroupComboBox *pCB = dynamic_cast(pCaller->getParent()); if (pCB == NULL) return; // if no choice, return. if( pCB->getNumTexts()==0 ) return; // get the menu to open. CGroupMenu *groupMenu= dynamic_cast(CWidgetManager::getInstance()->getElementFromId( CDBGroupComboBox::selectMenu )); if( !groupMenu ) { groupMenu= dynamic_cast(CWidgetManager::getInstance()->getElementFromId( CDBGroupComboBox::selectMenuOut )); } if( !groupMenu ) return; pCB->fillMenu(groupMenu); groupMenu->setMaxVisibleLine(8); // pos and size wisely the menu. groupMenu->setMinW(pCB->getWReal()); groupMenu->setX(pCB->getXReal()); groupMenu->setBaseX(pCB->getXReal()); groupMenu->setY(pCB->getYReal()); groupMenu->setBaseY(pCB->getYReal()); // Must ensure the combo menu has same windows priority than the combo box window CInterfaceGroup *rootWin= pCB->getRootWindow(); if(rootWin) groupMenu->setPriority(rootWin->getPriority()); // After menu init, Call user activation method if( !pCB->_AHOnSelectStart.empty() ) { CAHManager::getInstance()->runActionHandler(pCB->_AHOnSelectStart, pCB); } // launch the menu // if the combo box is in a modal, must do a push, else just replace if(dynamic_cast(pCB->getRootWindow())) { groupMenu->setCloseSubMenuUsingPopModal(true); CWidgetManager::getInstance()->pushModalWindow(pCB, groupMenu); } else { groupMenu->setCloseSubMenuUsingPopModal(false); CWidgetManager::getInstance()->enableModalWindow (pCB, groupMenu); } } }; REGISTER_ACTION_HANDLER (CHandlerComboBoxSelectStart, "combo_box_select_start"); // *************************************************************************** class CHandlerComboBoxSelectEnd : public IActionHandler { public: virtual void execute (CCtrlBase * /* pCaller */, const std::string &Params) { CDBGroupComboBox *pCB = dynamic_cast(CWidgetManager::getInstance()->getCtrlLaunchingModal()); if (pCB == NULL) return; // set the selection sint32 selection; fromString(Params, selection); pCB->setSelection(selection); } }; REGISTER_ACTION_HANDLER (CHandlerComboBoxSelectEnd, "combo_box_select_end"); }