diff --git a/code/nel/include/nel/gui/group_menu.h b/code/nel/include/nel/gui/group_menu.h index ecdd8aff0..51efaacb6 100644 --- a/code/nel/include/nel/gui/group_menu.h +++ b/code/nel/include/nel/gui/group_menu.h @@ -136,9 +136,13 @@ namespace NLGUI void removeLine(uint index); const std::string getActionHandler(uint lineIndex) const; const std::string getActionHandlerParam(uint lineIndex) const; + const std::string getRightClickHandler(uint lineIndex) const; + const std::string getRightClickHandlerParam(uint lineIndex) const; void setActionHandler(uint lineIndex, const std::string &ah = ""); void setActionHandlerParam(uint lineIndex, const std::string ¶ms = ""); + void setRightClickHandler(uint lineIndex, const std::string &ah = ""); + void setRightClickHandlerParam(uint lineIndex, const std::string ¶ms = ""); void openSubMenu (sint32 nb); @@ -235,6 +239,8 @@ namespace NLGUI CInterfaceGroup *Separator; std::string AHName; std::string AHParams; + std::string AHRightClick; + std::string AHRightClickParams; std::string Id; std::string Cond; // condition to know if the entry is grayed CViewBitmap *CheckBox; @@ -332,9 +338,13 @@ namespace NLGUI void deleteLine(uint index); const std::string getActionHandler(uint lineIndex) const; const std::string getActionHandlerParam(uint lineIndex) const; + const std::string getRightClickHandler(uint lineIndex) const; + const std::string getRightClickHandlerParam(uint lineIndex) const; void setActionHandler(uint lineIndex, const std::string &ah = ""); void setActionHandlerParam(uint lineIndex, const std::string ¶ms = ""); + void setRightClickHandler(uint lineIndex, const std::string &ah = ""); + void setRightClickHandlerParam(uint lineIndex, const std::string ¶ms = ""); void addLine (const ucstring &name, const std::string &ah = "", const std::string ¶ms = "", const std::string &id = std::string(), diff --git a/code/nel/src/gui/group_menu.cpp b/code/nel/src/gui/group_menu.cpp index 15a655d76..79be55110 100644 --- a/code/nel/src/gui/group_menu.cpp +++ b/code/nel/src/gui/group_menu.cpp @@ -1038,6 +1038,18 @@ namespace NLGUI } } + if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup) + { + // If a line is selected and the line is not grayed and has right click action handler + if ((_Selected != -1) && (!_Lines[i].ViewText->getGrayed()) && !_Lines[_Selected].AHRightClick.empty()) + { + CAHManager::getInstance()->runActionHandler ( _Lines[_Selected].AHRightClick, + CWidgetManager::getInstance()->getCtrlLaunchingModal(), + _Lines[_Selected].AHRightClickParams ); + return true; + } + } + if (event.getType() == NLGUI::CEventDescriptor::mouse) { const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event; @@ -1685,6 +1697,28 @@ namespace NLGUI _Lines[lineIndex].AHParams = params; } + // ------------------------------------------------------------------------------------------------ + void CGroupSubMenu::setRightClickHandler(uint lineIndex, const std::string &ah) + { + if (lineIndex > _Lines.size()) + { + nlwarning("Bad index"); + return; + } + _Lines[lineIndex].AHRightClick = ah; + } + + // ------------------------------------------------------------------------------------------------ + void CGroupSubMenu::setRightClickHandlerParam(uint lineIndex, const std::string ¶ms) + { + if (lineIndex > _Lines.size()) + { + nlwarning("Bad index"); + return; + } + _Lines[lineIndex].AHRightClickParams = params; + } + // ------------------------------------------------------------------------------------------------ void CGroupSubMenu::setSelectable(uint lineIndex, bool selectable) { @@ -2632,6 +2666,20 @@ namespace NLGUI _RootMenu->setActionHandlerParam(lineIndex, params); } + // ------------------------------------------------------------------------------------------------ + void CGroupMenu::setRightClickHandler(uint lineIndex, const std::string &ah) + { + if (_RootMenu) + _RootMenu->setRightClickHandler(lineIndex, ah); + } + + // ------------------------------------------------------------------------------------------------ + void CGroupMenu::setRightClickHandlerParam(uint lineIndex, const std::string ¶ms) + { + if (_RootMenu) + _RootMenu->setRightClickHandlerParam(lineIndex, params); + } + // ------------------------------------------------------------------------------------------------ void CGroupMenu::setUserGroupRight(uint line, CInterfaceGroup *gr, bool ownerShip /*=true*/) { diff --git a/code/ryzom/client/src/interface_v3/action_handler_base.cpp b/code/ryzom/client/src/interface_v3/action_handler_base.cpp index fcb66b1bc..2fbe4c662 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_base.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_base.cpp @@ -23,6 +23,7 @@ #include "nel/gui/group_container.h" #include "nel/gui/group_editbox.h" +#include "nel/gui/group_menu.h" #include "dbctrl_sheet.h" #include "interface_3d_scene.h" #include "character_3d.h" @@ -74,7 +75,31 @@ class CAHActiveMenu : public IActionHandler // open the menu if (CDBCtrlSheet::getDraggedSheet() == NULL) { - CWidgetManager::getInstance()->enableModalWindow (pCaller, getParam(Params, "menu")); + std::string menuId = getParam(Params, "menu"); + CGroupMenu *groupMenu = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(menuId)); + if (groupMenu) + { + bool pushModal; + // default = false + fromString(getParam(Params, "pushmodal"), pushModal); + + if (pushModal) + { + // if false, then close all modal window when groupMenu deactivates + bool popModal; + if (!fromString(getParam(Params, "popmodal"), popModal)) + { + popModal = true; + } + groupMenu->setCloseSubMenuUsingPopModal(popModal); + CWidgetManager::getInstance()->pushModalWindow(pCaller, groupMenu); + } + else + { + groupMenu->setCloseSubMenuUsingPopModal(false); + CWidgetManager::getInstance()->enableModalWindow(pCaller, groupMenu); + } + } } } }; diff --git a/code/ryzom/client/src/interface_v3/group_map.cpp b/code/ryzom/client/src/interface_v3/group_map.cpp index 4b4be518d..66c967353 100644 --- a/code/ryzom/client/src/interface_v3/group_map.cpp +++ b/code/ryzom/client/src/interface_v3/group_map.cpp @@ -2660,6 +2660,9 @@ static void hideTeleportButtonsInPopupMenuIfNotEnoughPriv() ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu:lmteleport"); if(ie) ie->setActive(showTeleport); + + ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu_base:lmteleport"); + if(ie) ie->setActive(showTeleport); } //============================================================================================================ @@ -2723,8 +2726,8 @@ CGroupMap::CLandMarkButton *CGroupMap::createLandMarkButton(const CLandMarkOptio lmb->setModulateGlobalColorAll(false); if (!options.LandMarkMenu.empty()) { - lmb->setActionOnRightClick("active_menu"); - lmb->setParamsOnRightClick(NLMISC::toString("menu=%s", options.LandMarkMenu.c_str())); + lmb->setActionOnRightClick("world_map_right_click"); + lmb->setParamsOnRightClick(NLMISC::toString("map=%s|menu=%s", _Id.c_str(), options.LandMarkMenu.c_str())); } lmb->setPosRef(Hotspot_MM); return lmb; @@ -2876,6 +2879,23 @@ CCtrlButton *CGroupMap::addUserLandMark(const NLMISC::CVector2f &pos, const ucst return _UserLM.back(); } +//============================================================================================================ +CCtrlButton* CGroupMap::getLandmarkCtrl(const std::string &lmType, uint lmIndex) const +{ + CCtrlButton *ctrl = NULL; + if (lmType == "user") + { + if (lmIndex < _UserLM.size()) + { + ctrl = _UserLM[lmIndex]; + } + else nlwarning("_UserLM index out of bounds (size:%u, index:%u)", (uint)_UserLM.size(), lmIndex); + } + else nlwarning("unsupported landmark type '%s'", lmType.c_str()); + + return ctrl; +} + //============================================================================================================ void CGroupMap::removeUserLandMark(CCtrlButton *button) { @@ -3721,6 +3741,126 @@ int CGroupMap::luaIsIsland(CLuaState &ls) // ACTION HANDLERS // ///////////////////// +//========================================================================================================= +void CGroupMap::updateClosestLandMarkMenu(const std::string &menu, const NLMISC::CVector2f &pos) const +{ + static uint nbShowLandmarks = 5; + static uint nbShowLandmarksMax = 5; + + const CGroupMenu *pMenu = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(menu)); + if (!pMenu) return; + + CGroupSubMenu *rootMenu = pMenu->getRootMenu(); + if (!rootMenu) return; + + // remove previous markers from menu + for(uint i = 0; i < nbShowLandmarksMax; ++i) + { + std::string lineId = toString("%s:lmcosest%d", menu.c_str(), i); + sint index = rootMenu->getLineFromId(lineId); + if (index < 0) break; + rootMenu->removeLine(index); + } + + // no continent selected (ie world map view) + if (!_CurContinent) return; + + // sort landmarks, keep indices + typedef std::pair TSortedDistPair; + std::vector sortedIndices; + for(uint i = 0; i < _CurContinent->UserLandMarks.size(); ++i) + { + float dist = distsqr(pos, _CurContinent->UserLandMarks[i].Pos); + if (sortedIndices.empty()) + { + sortedIndices.push_back(TSortedDistPair(i, dist)); + } + else + { + bool found = false; + for(uint j = 0; j< sortedIndices.size(); j++) + { + if (dist < sortedIndices[j].second) + { + sortedIndices.insert(sortedIndices.begin() + j, TSortedDistPair(i, dist)); + found = true; + if (sortedIndices.size() > nbShowLandmarks) + { + sortedIndices.pop_back(); + } + break; + } + } + + if (!found && sortedIndices.size() < nbShowLandmarks) + { + sortedIndices.push_back(TSortedDistPair(i, dist)); + } + } + } + + // add landmarks to menu + uint lineIndex = rootMenu->getNumLines(); + for(uint i = 0; i< sortedIndices.size(); ++i) + { + uint32 index = sortedIndices[i].first; + ucstring name = ucstring(toString("%.2fm ", sqrt(sortedIndices[i].second))) + _CurContinent->UserLandMarks[index].Title; + std::string lineId = toString("%s:lmcosest%d", menu.c_str(), i); + std::string ahParams = toString("type=user|map=%s|index=%d", _Id.c_str(), index); + + CViewTextMenu* vt = rootMenu->addLine(ucstring(""), "map_landmark_by_index", ahParams, lineId.c_str(), "", "", false, false, false); + if (!vt) break; + + vt->setSingleLineTextFormatTaged(name); + // TODO: should calculate from mouse pos and client width + vt->setLineMaxW(800); + + CLandMarkOptions options = getUserLandMarkOptions(index); + + typedef std::pair TTmplParams; + std::vector vparams; + vparams.push_back(TTmplParams("id", toString("lmicon%d", i))); + vparams.push_back(TTmplParams("sizeref", "")); + vparams.push_back(TTmplParams("icon_texture", options.LandMarkTexNormal)); + vparams.push_back(TTmplParams("icon_color", options.ColorNormal.toString())); + + CInterfaceGroup *pUGLeft = CWidgetManager::getInstance()->getParser()->createGroupInstance("landmark_row_icon", lineId, vparams); + if (pUGLeft) + rootMenu->setUserGroupLeft(lineIndex, pUGLeft, true); + + rootMenu->setRightClickHandler(lineIndex, "map_landmark_by_index"); + rootMenu->setRightClickHandlerParam(lineIndex, toString("%s|menu=%s_base", ahParams.c_str(), options.LandMarkMenu.c_str())); + lineIndex++; + } +} + +//========================================================================================================= +// remap caller with landmark using index/type and call popup menu or set compass target if no menu is set +class CAHMapLandmarkByIndex : public IActionHandler +{ + virtual void execute (CCtrlBase* pCaller, const string ¶ms ) + { + const std::string mapName = getParam(params, "map"); + const std::string lmType = getParam(params, "type"); + const std::string menuId = getParam(params, "menu"); + uint index; + if (!fromString(getParam(params, "index"), index)) return; + + CGroupMap *map = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(mapName)); + if (!map) return; + + // remap caller to landmark from menu row + CCtrlButton* pButton = map->getLandmarkCtrl(lmType, index); + if (!pButton) return; + + if (menuId.empty()) + map->targetLandmark(pButton); + else + CAHManager::getInstance()->runActionHandler("active_menu", pButton, toString("pushmodal=true|popmodal=false|menu=%s", menuId.c_str())); + } +}; +REGISTER_ACTION_HANDLER(CAHMapLandmarkByIndex, "map_landmark_by_index"); + //========================================================================================================= // Set landmark filter class CAHLandMarkFilter : public IActionHandler @@ -4025,23 +4165,41 @@ class CAHWorldMapRightClick : public IActionHandler virtual void execute (CCtrlBase *pCaller, const string ¶ms) { std::string map = getParam(params, "map"); - CInterfaceManager *im = CInterfaceManager::getInstance(); + std::string menu = getParam(params, "menu"); hideTeleportButtonsInPopupMenuIfNotEnoughPriv(); CGroupMap *gm = dynamic_cast(CWidgetManager::getInstance()->getElementFromId(map)); if (!gm) return; - if (!gm->isIsland()) + + if (gm->isIsland()) { - CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=ui:interface:map_menu"); + if (gm->getArkPowoMode() == "editor") + menu = gm->getArkPowoMapMenu(); + else + menu = "ui:interface:map_menu_island"; } else { - if (gm->getArkPowoMode() == "editor") - CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu="+gm->getArkPowoMapMenu()); - else - CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=ui:interface:map_menu_island"); + if (menu.empty()) + menu = "ui:interface:map_menu"; + + // update menu with closest landmarks + NLMISC::CVector2f pos(NLMISC::CVector2f::Null); + CCtrlButton *button = dynamic_cast(pCaller); + if (button) + gm->getLandmarkPosition(button, pos); + + if(pos == NLMISC::CVector2f::Null) + { + pos = gm->getRightClickLastPos(); + gm->mapToWorld(pos, pos); + } + + gm->updateClosestLandMarkMenu(menu, pos); } + + CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=" + menu); } }; REGISTER_ACTION_HANDLER(CAHWorldMapRightClick, "world_map_right_click") diff --git a/code/ryzom/client/src/interface_v3/group_map.h b/code/ryzom/client/src/interface_v3/group_map.h index d6f54cd7e..2bc112c5b 100644 --- a/code/ryzom/client/src/interface_v3/group_map.h +++ b/code/ryzom/client/src/interface_v3/group_map.h @@ -199,6 +199,8 @@ public: float getScale() const { return _UserScale; } /// add a user landmark (returns a pointer on its button).Coordinate are in the current map (not world coordinates) CCtrlButton *addUserLandMark(const NLMISC::CVector2f &pos, const ucstring &title, const CUserLandMark::EUserLandMarkType lmType); + /// return current continent landmark by its index and type + CCtrlButton* getLandmarkCtrl(const std::string &lmType, uint lmIndex) const; // remove a user landmark from a pointer on its button void removeUserLandMark(CCtrlButton *button); // update a user landmark from a pointer on its button @@ -295,6 +297,8 @@ public: bool isIsland() const { return _IsIsland; } + void updateClosestLandMarkMenu(const std::string &menu, const NLMISC::CVector2f &pos) const; + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private: // A non rectangular button to click on zone of the map