// 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/action_handler.h" #include "nel/gui/group_container_base.h" #include "nel/gui/interface_property.h" #include "nel/gui/interface_expr.h" #include "nel/gui/db_manager.h" #include "nel/gui/interface_link.h" #include "nel/gui/widget_manager.h" using namespace std; using namespace NLMISC; namespace NLGUI { // ------------------------------------------------------------------------------------------------ CAHManager *CAHManager::_GlobalInstance = NULL; bool CAHManager::editorMode = false; // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ static void skipBlankAtStart (string &start) { while (!start.empty()) { if ((start[0] == ' ' || start[0] == '\t' || start[0] == '\r' || start[0] == '\n')) start = start.substr(1,start.size()); else break; } } // ------------------------------------------------------------------------------------------------ static void skipBlankAtEnd (string &end) { while (!end.empty()) { if ((end[end.size()-1] == ' ' || end[end.size()-1] == '\t' || end[end.size()-1] == '\r' || end[end.size()-1] == '\n')) end = end.substr(0,end.size()-1); else break; } } // ------------------------------------------------------------------------------------------------ std::string IActionHandler::getParam (const string &Params, const string &ParamName) { string allparam = Params; skipBlankAtStart (allparam); string param = toLower (ParamName); while (allparam.size() > 0) { std::string::size_type e = allparam.find('='); if (e == std::string::npos || e == 0) break; std::string::size_type p = allparam.find('|'); string tmp = NLMISC::toLower(allparam.substr(0,e)); skipBlankAtEnd(tmp); if (tmp == param) { string tmp2 = allparam.substr(e+1,p-e-1); skipBlankAtStart(tmp2); skipBlankAtEnd(tmp2); return tmp2; } if (p == std::string::npos || p == 0) break; allparam = allparam.substr(p+1,allparam.size()); skipBlankAtStart (allparam); } return ""; } // ------------------------------------------------------------------------------------------------ void IActionHandler::getAllParams (const string &Params, vector< pair > &vAllParams) { string allparam = Params; skipBlankAtStart (allparam); while (allparam.size() > 0) { std::string::size_type e = allparam.find('='); if (e == std::string::npos || e == 0) break; std::string::size_type p = allparam.find('|'); string tmp = NLMISC::toLower(allparam.substr(0,e)); skipBlankAtEnd(tmp); string tmp2 = allparam.substr(e+1,p-e-1); skipBlankAtStart(tmp2); skipBlankAtEnd(tmp2); vAllParams.push_back(pair(tmp,tmp2)); if (p == std::string::npos || p == 0) break; allparam = allparam.substr(p+1,allparam.size()); skipBlankAtStart (allparam); } } // ------------------------------------------------------------------------------------------------ IActionHandler* CAHManager::getAH(const std::string &name, std::string ¶ms) { // Special AH form? string::size_type i= name.find(':'); if(i!=string::npos) { string ahName= name.substr(0, i); params= name.substr(i+1); return getActionHandler(ahName); } // standalone form else return getActionHandler(name); } // ------------------------------------------------------------------------------------------------ IActionHandler* CAHManager::getAH(const std::string &name, CStringShared ¶ms) { // Special AH form? string::size_type i= name.find(':'); if(i!=string::npos) { string ahName= name.substr(0, i); params= name.substr(i+1); return getActionHandler(ahName); } // standalone form else return getActionHandler(name); } // ------------------------------------------------------------------------------------------------ void CAHManager::parseAH(xmlNodePtr cur, const char *ahId, const char *paramId, IActionHandler *&ahRet, std::string ¶mRet) { CXMLAutoPtr prop; // Read the action handler and any param he defines bool paramSpecifiedInAH= false; if(ahId) { prop = (char*) xmlGetProp( cur, (xmlChar*)ahId ); if (prop) { string ahVal= (const char*)prop; if(ahVal.find(':')!= string::npos) paramSpecifiedInAH= true; ahRet = getAH(ahVal, paramRet); } } // Read parameter (if specified) if(paramId) { prop = (char*) xmlGetProp( cur, (xmlChar*)paramId ); /* Precise stuff here (for legacy rules): If the param is not specified in the ahId, then replace params. But if it is specified, don't replace it if the prop is empty!! Because this cause problems with template and parameter replacement. */ if ((const char *)prop && (!paramSpecifiedInAH || strlen((const char*)prop)>0) ) paramRet = string((const char*)prop); } } void CAHManager::parseAH(xmlNodePtr cur, const char *ahId, const char *paramId, IActionHandler *&ahRet, CStringShared ¶mRet) { CXMLAutoPtr prop; // Read the action handler and any param he defines bool paramSpecifiedInAH= false; if(ahId) { prop = (char*) xmlGetProp( cur, (xmlChar*)ahId ); if (prop) { string ahVal= (const char*)prop; if(ahVal.find(':')!= string::npos) paramSpecifiedInAH= true; ahRet = getAH(ahVal, paramRet); } } // Read parameter (if specified) if(paramId) { prop = (char*) xmlGetProp( cur, (xmlChar*)paramId ); /* Precise stuff here (for legacy rules): If the param is not specified in the ahId, then replace params. But if it is specified, don't replace it if the prop is empty!! Because this cause problems with template and parameter replacement. */ if ((const char *)prop && (!paramSpecifiedInAH || strlen((const char*)prop)>0) ) paramRet = string((const char*)prop); } } // ------------------------------------------------------------------------------------------------ void CAHManager::runActionHandler (const string &ahCmdLine, CCtrlBase *pCaller, const string &ahUserParams) { if (ahCmdLine.empty()) return; if( editorMode ) return; // Special AH form ("ah:params") ? string::size_type i = ahCmdLine.find(':'); string ahName; string ahParams; if(i!=string::npos) { ahName= ahCmdLine.substr(0, i); ahParams= ahCmdLine.substr(i+1); } else { ahName= ahCmdLine; } // Replace params if defined if(!ahUserParams.empty()) ahParams= ahUserParams; // Execute the action handler map::iterator it = FactoryMap.find (ahName); if (it == FactoryMap.end()) { nlwarning ("not found action handler : %s",ahName.c_str()); return; } IActionHandler *pAH = it->second; pAH->execute (pCaller, ahParams); // Quick Help const string submitQuickHelp = "submit_quick_help"; it = FactoryMap.find(submitQuickHelp); if(it == FactoryMap.end()) { nlwarning ("not found action handler : %s", submitQuickHelp.c_str()); return; } pAH = it->second; const std::string event = ahName + ":" + ahParams; pAH->execute(NULL, event); } // ------------------------------------------------------------------------------------------------ void CAHManager::runActionHandler (IActionHandler *pAH, CCtrlBase *pCaller, const std::string &Params) { if (pAH == NULL) { nlwarning ("no action handler"); return; } if( editorMode ) return; pAH->execute (pCaller, Params); string AHName = CAHManager::getInstance()->getAHName(pAH); // Quick Help const string submitQuickHelp = "submit_quick_help"; map::iterator it = FactoryMap.find (AHName); it = FactoryMap.find(submitQuickHelp); if(it == FactoryMap.end()) { nlwarning ("not found action handler : %s", submitQuickHelp.c_str()); return; } pAH = it->second; const std::string event = AHName + ":" + Params; pAH->execute(NULL, event); } void CAHManager::submitEvent( const std::string &evt ) { // Submit the event to the quick help system runActionHandler( "submit_quick_help", NULL, evt ); } // ------------------------------------------------------------------------------------------------ class CAHSet : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &Params) { string dblink = getParam (Params, "dblink"); string property = getParam (Params, "target_property"); string propertyToEval = getParam (Params, "target"); string expr = getParam (Params, "value"); //nlinfo("set %s %s %s %s", dblink.c_str(), property.c_str(), propertyToEval.c_str(), expr.c_str()); CInterfaceExprValue value; if (CInterfaceExpr::eval(expr, value, NULL)) { if (!dblink.empty()) { // Do not allow Write on SERVER: or LOCAL: static const std::string dbServer= "SERVER:"; static const std::string dbLocal= "LOCAL:"; static const std::string dbLocalR2= "LOCAL:R2"; if( (0==dblink.compare(0, dbServer.size(), dbServer)) || (0==dblink.compare(0, dbLocal.size(), dbLocal)) ) { if (0!=dblink.compare(0, dbLocalR2.size(), dbLocalR2)) { //nlwarning("You are not allowed to write on 'SERVER:...' or 'LOCAL:...' database"); nlstop; return; } } string dblinkeval; CInterfaceExpr::unpackDBentry(dblink.c_str(), NULL, dblinkeval); if (!value.toInteger()) { nlwarning(" expression doesn't evaluate to a numerical value"); } CInterfaceProperty ip; if (!value.toInteger()) { nlwarning(" expression doesn't evaluate to a numerical value"); } if (ip.link (dblinkeval.c_str())) { ip.setSInt64(value.getInteger()); } } if (!propertyToEval.empty()) { CInterfaceExprValue res; if (!CInterfaceExpr::eval(propertyToEval, res, NULL)) return; res.toString(); property = res.getString(); } if (!property.empty()) { std::vector targets; // find first enclosing group CCtrlBase *currCtrl = pCaller; CInterfaceGroup *ig = NULL; while (currCtrl) { ig = dynamic_cast(currCtrl); if (ig != NULL) break; currCtrl = currCtrl->getParent(); } if (ig == NULL) { string elt = property.substr(0,property.rfind(':')); CInterfaceElement *pIE = CWidgetManager::getInstance()->getElementFromId(elt); ig = dynamic_cast(pIE); if (ig == NULL && pIE != NULL) ig = pIE->getParent(); } if (ig != NULL) { CInterfaceLink::splitLinkTargets(property, ig, targets); for(uint k = 0; k < targets.size(); ++k) { if (targets[k].Elem) targets[k].affect(value); } } } } else { nlwarning(" Couldn't evaluate expression to affect, expr = %s", expr.c_str()); } } }; REGISTER_ACTION_HANDLER (CAHSet, "set"); // ------------------------------------------------------------------------------------------------ class CAHCopy : public IActionHandler { public: virtual void execute (CCtrlBase * /* pCaller */, const string &Params) { string dbdst = getParam (Params, "dbdst"); string dbsrc = getParam (Params, "dbsrc"); CCDBNodeBranch *pNBdst = NLGUI::CDBManager::getInstance()->getDbBranch(dbdst); CCDBNodeBranch *pNBsrc = NLGUI::CDBManager::getInstance()->getDbBranch(dbsrc); // Branch copy if ((pNBdst != NULL) && (pNBsrc != NULL)) { //nlinfo("copying from %s to %s",pNBsrc->getName()->c_str(), pNBdst->getName()->c_str()); // Parse all children of the src branch uint nbLeaves = pNBsrc->countLeaves(); for (uint i = 0; i < nbLeaves; ++i) { uint count = i; CCDBNodeLeaf *pNLsrc = pNBsrc->findLeafAtCount(count); // Find its access name string sTmp = *pNLsrc->getName(); CCDBNodeBranch *pParent = pNLsrc->getParent(); while (pParent != pNBsrc) { sTmp = *pParent->getName() + ":" + sTmp; pParent = pParent->getParent(); } // Find the correspondant node in the dst branch CCDBNodeLeaf *pNLdst = dynamic_cast(pNBdst->getNode(ICDBNode::CTextId(sTmp))); if (pNLdst == NULL) { nlwarning ("cannot find destination leaf %s",sTmp.c_str()); } else { pNLdst->setValue64(pNLsrc->getValue64()); //sint32 nVal = pNLsrc->getValue64(); //nlinfo("set value %d for node %s", nVal, sTmp.c_str()); } } return; } // Not branch copy so leaf copy CInterfaceProperty ipsrc; CInterfaceProperty ipdst; if (!ipsrc.link (dbsrc.c_str())) { nlwarning("cannot find leaf %s",dbsrc.c_str()); return; } if (!ipdst.link (dbdst.c_str())) { nlwarning("cannot find leaf %s",dbdst.c_str()); return; } // copy ipdst.setSInt64 (ipsrc.getSInt64()); } }; REGISTER_ACTION_HANDLER (CAHCopy, "copy"); // ------------------------------------------------------------------------------------------------ class CAHResizeW : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const string &Params) { string elt = getParam (Params, "elt"); sint32 value; fromString(getParam(Params, "value"), value); sint32 limit; fromString(getParam(Params, "limit"), limit); CInterfaceElement *pIE = CWidgetManager::getInstance()->getElementFromId (pCaller->getId(), elt); if (pIE == NULL) return; sint32 newW = pIE->getW(); newW += value; if (value < 0) { if (newW < limit) newW = limit; } else { if (newW > limit) newW = limit; } pIE->setW (newW); pIE->invalidateCoords(); } }; REGISTER_ACTION_HANDLER (CAHResizeW, "resize_w"); //////////////////////////////// // EDITION OF CONTAINER ALPHA // //////////////////////////////// // the container whose alpha is being edited static CGroupContainerBase *AlphaChooserTarget = NULL; static bool OldUseGlobalAlpha; static uint8 OldContentAlpha; static uint8 OldBgAlpha; static uint8 OldRolloverAlphaBG; static uint8 OldRolloverAlphaContent; // observer to change the container alpha class CContainerAlphaObserver : public ICDBNode::IPropertyObserver { public: bool On; enum TTargetAlpha { ContentAlpha = 0, BgAlpha, RolloverAlphaContent, RolloverAlphaBG }; TTargetAlpha Target; virtual void update(ICDBNode *node) { if (!On) return; if (!AlphaChooserTarget) return; CCDBNodeLeaf *leaf = safe_cast(node); switch(Target) { case ContentAlpha: AlphaChooserTarget->setContentAlpha((uint8) leaf->getValue32()); break; case BgAlpha: AlphaChooserTarget->setContainerAlpha((uint8) leaf->getValue32()); break; case RolloverAlphaContent: AlphaChooserTarget->setRolloverAlphaContent((uint8) (255 - (uint8) leaf->getValue32())); break; case RolloverAlphaBG: AlphaChooserTarget->setRolloverAlphaContainer((uint8) (255 - (uint8) leaf->getValue32())); break; } } }; // ------------------------------------------------------------------------------------------------ class CAHChooseUIAlpha : public IActionHandler { public: virtual void execute (CCtrlBase *pCaller, const std::string &/* Params */) { CGroupContainerBase *gc = NULL; CCtrlBase *cb = pCaller; while (cb) { gc = dynamic_cast(cb); if (gc) break; cb = cb->getParent(); } if (!gc) return; AlphaChooserTarget = gc; if (!_AlphaObserversAdded) { _UiVariableBGAlpha = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:ALPHA_BG"); _UiVariableContentAlpha = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:ALPHA_CONTENT"); _UiVariableRolloverAlphaBG = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:ALPHA_ROLLOVER_BG"); _UiVariableRolloverAlphaContent = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:ALPHA_ROLLOVER_CONTENT"); ICDBNode::CTextId textIdBGAlpha, textIdContentAlpha, textIdRolloverAlphaBG, textIdRolloverAlphaContent; _UiVariableBGAlpha->addObserver(&_BgAlphaObs, textIdBGAlpha); _UiVariableContentAlpha->addObserver(&_ContentAlphaObs, textIdContentAlpha); _UiVariableRolloverAlphaBG->addObserver(&_RolloverAlphaBGObs, textIdRolloverAlphaBG); _UiVariableRolloverAlphaContent->addObserver(&_RolloverAlphaContentObs, textIdRolloverAlphaContent); _AlphaObserversAdded = true; } // disable observers _ContentAlphaObs.On = false; _BgAlphaObs.On = false; _RolloverAlphaBGObs.On = false; _RolloverAlphaContentObs.On = false; // set alpha of current chosen container _UiVariableBGAlpha->setValue32(gc->getContainerAlpha()); _UiVariableContentAlpha->setValue32(gc->getContentAlpha()); _UiVariableRolloverAlphaBG->setValue32(255 - gc->getRolloverAlphaContainer()); _UiVariableRolloverAlphaContent->setValue32(255 - gc->getRolloverAlphaContent()); // enable observers _ContentAlphaObs.On = true; _BgAlphaObs.On = true; _RolloverAlphaBGObs.On = true; _RolloverAlphaContentObs.On = true; // backup current alpha (if the user cancel) OldContentAlpha = gc->getContentAlpha(); OldBgAlpha = gc->getContainerAlpha(); OldRolloverAlphaBG = gc->getRolloverAlphaContainer(); OldRolloverAlphaContent = gc->getRolloverAlphaContent(); OldUseGlobalAlpha = gc->isUsingGlobalAlpha(); // Enable 'use global alpha' button NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:USER_ALPHA")->setValue64(gc->isUsingGlobalAlpha() ? 0 : 1); // show the modal box CWidgetManager::getInstance()->enableModalWindow(gc, "ui:interface:define_ui_transparency"); } CAHChooseUIAlpha() { _UiVariableContentAlpha = NULL; _UiVariableBGAlpha = NULL; _UiVariableRolloverAlphaBG = NULL; _UiVariableRolloverAlphaContent = NULL; _AlphaObserversAdded = false; _BgAlphaObs.Target = CContainerAlphaObserver::BgAlpha; _ContentAlphaObs.Target = CContainerAlphaObserver::ContentAlpha; _RolloverAlphaBGObs.Target = CContainerAlphaObserver::RolloverAlphaBG; _RolloverAlphaContentObs.Target = CContainerAlphaObserver::RolloverAlphaContent; } private: // instance of observer to copy alpha from db to a container CContainerAlphaObserver _ContentAlphaObs; CContainerAlphaObserver _BgAlphaObs; CContainerAlphaObserver _RolloverAlphaContentObs; CContainerAlphaObserver _RolloverAlphaBGObs; // flag to know if observer have been added bool _AlphaObserversAdded; // db leaf that contains alpha for the current container CCDBNodeLeaf *_UiVariableContentAlpha; CCDBNodeLeaf *_UiVariableBGAlpha; CCDBNodeLeaf *_UiVariableRolloverAlphaContent; CCDBNodeLeaf *_UiVariableRolloverAlphaBG; }; REGISTER_ACTION_HANDLER (CAHChooseUIAlpha, "choose_ui_alpha"); // ------------------------------------------------------------------------------------------------ class CAHCancelChooseUIAlpha : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const std::string &/* Params */) { if (AlphaChooserTarget) { AlphaChooserTarget->setUseGlobalAlpha(OldUseGlobalAlpha); AlphaChooserTarget->setContainerAlpha(OldBgAlpha); AlphaChooserTarget->setContentAlpha(OldContentAlpha); AlphaChooserTarget->setRolloverAlphaContainer(OldRolloverAlphaBG); AlphaChooserTarget->setRolloverAlphaContent(OldRolloverAlphaContent); } } }; REGISTER_ACTION_HANDLER (CAHCancelChooseUIAlpha, "cancel_choose_ui_alpha"); // ------------------------------------------------------------------------------------------------ class CAHUseGlobalAlphaSettings : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const std::string &/* Params */) { if (AlphaChooserTarget) { AlphaChooserTarget->setUseGlobalAlpha(!AlphaChooserTarget->isUsingGlobalAlpha()); NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:USER_ALPHA")->setValue64(AlphaChooserTarget->isUsingGlobalAlpha() ? 0 : 1); } } }; REGISTER_ACTION_HANDLER (CAHUseGlobalAlphaSettings, "use_global_alpha_settings"); // ------------------------------------------------------------------------------------------------ class CAHLockUnlock : public IActionHandler { virtual void execute (CCtrlBase *pCaller, const std::string &/* Params */) { CGroupContainerBase *gc = NULL; CCtrlBase *cb = pCaller; while (cb) { gc = dynamic_cast< CGroupContainerBase* >(cb); if (gc) break; cb = cb->getParent(); } if (!gc) return; //gc->setMovable(!gc->isMovable()); gc->setLocked(!gc->isLocked()); } }; REGISTER_ACTION_HANDLER (CAHLockUnlock, "lock_unlock"); // ------------------------------------------------------------------------------------------------ class CAHSetTransparent : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const std::string &Params) { CGroupContainerBase *pGC = dynamic_cast< CGroupContainerBase* >(CWidgetManager::getInstance()->getElementFromId(Params)); if (pGC != NULL) { pGC->setUseGlobalAlpha(false); pGC->setContainerAlpha((uint8) 0); pGC->setContentAlpha((uint8) 255); pGC->setRolloverAlphaContainer((uint8) 255); pGC->setRolloverAlphaContent((uint8) 0); } } }; REGISTER_ACTION_HANDLER (CAHSetTransparent, "set_transparent"); // ------------------------------------------------------------------------------------------------ class CAHSetAlpha : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const std::string &Params) { string ui = getParam (Params, "target"); uint8 alpha; fromString(getParam (Params, "alpha"), alpha); CGroupContainerBase *pGC = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(ui)); if (pGC != NULL) { pGC->setUseGlobalAlpha(false); pGC->setContainerAlpha((uint8) alpha); pGC->setContentAlpha((uint8) 255); pGC->setRolloverAlphaContainer((uint8) 0); pGC->setRolloverAlphaContent((uint8) 0); } } }; REGISTER_ACTION_HANDLER (CAHSetAlpha, "set_alpha"); // ------------------------------------------------------------------------------------------------ class CAHUnlockAllContainer : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */) { const vector &rVMG = CWidgetManager::getInstance()->getAllMasterGroup(); for (uint32 nMasterGroup = 0; nMasterGroup < rVMG.size(); nMasterGroup++) { // const CInterfaceManager::SMasterGroup &rMG = rVMG[nMasterGroup]; CWidgetManager::getInstance()->getMasterGroup((uint8)nMasterGroup).unlockAllContainers(); } } }; REGISTER_ACTION_HANDLER (CAHUnlockAllContainer, "unlock_all_container"); }