From 78e1804381096395b6fe273c4eebac0e03951bbe Mon Sep 17 00:00:00 2001 From: Lirusaito Date: Fri, 8 Mar 2013 03:17:11 -0500 Subject: [PATCH] Add Pathfinding UI from v3 Added libpathing to LLPHYSICSEXTENSIONS_INCLUDE_DIRS llviewermenu updated a bit to be closer to v-d/rlva. Best viewed without space changes. Updated llresmgr.cpp from v-d to "handle special case of input value being zero" pipeline update: hideObject, restoreHiddenObject, hideDrawable, and unhideDrawable added. Thanks to Henri Beauchamp for some UI code touchups, thanks to Zi Ree for Rebake notification. Thanks to Mobius Ryba and Ansariel Hiller for the V1-style pathfinding icons. Note: When opening from pie menu object selection is lost, unless the floater is already open.. This provides a more reliable reproduction of the bug we've been having with inspect. --- indra/cmake/CMakeLists.txt | 1 + indra/cmake/LLPhysicsExtensions.cmake | 2 +- indra/llui/llresmgr.cpp | 7 + indra/newview/CMakeLists.txt | 6 + .../llfloaterpathfindingcharacters.cpp | 309 ++++++ .../newview/llfloaterpathfindingcharacters.h | 94 ++ .../newview/llfloaterpathfindinglinksets.cpp | 806 ++++++++++++++++ indra/newview/llfloaterpathfindinglinksets.h | 142 +++ indra/newview/llfloaterpathfindingobjects.cpp | 878 ++++++++++++++++++ indra/newview/llfloaterpathfindingobjects.h | 179 ++++ indra/newview/llpathfindingmanager.cpp | 13 +- indra/newview/llstatusbar.cpp | 80 +- indra/newview/llstatusbar.h | 9 + indra/newview/llviewermenu.cpp | 206 +++- indra/newview/llviewermenu.h | 16 +- indra/newview/pipeline.cpp | 69 +- indra/newview/pipeline.h | 6 +- indra/newview/skins/default/colors_base.xml | 10 + .../default/textures/Pathfinding_Dirty.png | Bin 0 -> 963 bytes .../default/textures/Pathfinding_Disabled.png | Bin 0 -> 1092 bytes .../en-us/floater_pathfinding_characters.xml | 226 +++++ .../en-us/floater_pathfinding_linksets.xml | 640 +++++++++++++ .../default/xui/en-us/menu_pie_object.xml | 10 + .../skins/default/xui/en-us/menu_viewer.xml | 20 +- .../skins/default/xui/en-us/notifications.xml | 171 +++- .../default/xui/en-us/panel_status_bar.xml | 6 + 26 files changed, 3811 insertions(+), 95 deletions(-) create mode 100644 indra/newview/llfloaterpathfindingcharacters.cpp create mode 100644 indra/newview/llfloaterpathfindingcharacters.h create mode 100644 indra/newview/llfloaterpathfindinglinksets.cpp create mode 100644 indra/newview/llfloaterpathfindinglinksets.h create mode 100644 indra/newview/llfloaterpathfindingobjects.cpp create mode 100644 indra/newview/llfloaterpathfindingobjects.h create mode 100644 indra/newview/skins/default/textures/Pathfinding_Dirty.png create mode 100644 indra/newview/skins/default/textures/Pathfinding_Disabled.png create mode 100644 indra/newview/skins/default/xui/en-us/floater_pathfinding_characters.xml create mode 100644 indra/newview/skins/default/xui/en-us/floater_pathfinding_linksets.xml diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index f22beca51..9eacfcada 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -68,6 +68,7 @@ set(cmake_SOURCE_FILES LLPhysicsExtensions.cmake LLPlugin.cmake LLPrimitive.cmake + LLPhysicsExtensions.cmake LLQtWebkit.cmake LLRender.cmake LLUI.cmake diff --git a/indra/cmake/LLPhysicsExtensions.cmake b/indra/cmake/LLPhysicsExtensions.cmake index 0e2d94316..919b0c343 100644 --- a/indra/cmake/LLPhysicsExtensions.cmake +++ b/indra/cmake/LLPhysicsExtensions.cmake @@ -1,7 +1,7 @@ # -*- cmake -*- set(LLPHYSICSEXTENSIONS_LIBRARIES nd_hacdConvexDecomposition hacd nd_Pathing ) -set(LLPHYSICSEXTENSIONS_INCLUDE_DIRS ${LIBS_OPEN_DIR}/libndhacd ) +set(LLPHYSICSEXTENSIONS_INCLUDE_DIRS ${LIBS_OPEN_DIR}/libndhacd ${LIBS_OPEN_DIR}/libpathing) diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index 07649adfa..334ead62a 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -383,6 +383,13 @@ std::string LLResMgr::getMonetaryString( S32 input ) const void LLResMgr::getIntegerString( std::string& output, S32 input ) const { + // handle special case of input value being zero + if (input == 0) + { + output = "0"; + return; + } + S32 fraction = 0; std::string fraction_string; S32 remaining_count = input; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7bb3a8950..f5c21590b 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -232,6 +232,9 @@ set(viewer_SOURCE_FILES llfloateropenobject.cpp llfloateroutbox.cpp llfloaterparcel.cpp + llfloaterpathfindingcharacters.cpp + llfloaterpathfindinglinksets.cpp + llfloaterpathfindingobjects.cpp llfloaterpermissionsmgr.cpp llfloaterperms.cpp llfloaterpostcard.cpp @@ -731,6 +734,9 @@ set(viewer_HEADER_FILES llfloateropenobject.h llfloateroutbox.h llfloaterparcel.h + llfloaterpathfindingcharacters.h + llfloaterpathfindinglinksets.h + llfloaterpathfindingobjects.h llfloaterpermissionsmgr.h llfloaterperms.h llfloaterpostcard.h diff --git a/indra/newview/llfloaterpathfindingcharacters.cpp b/indra/newview/llfloaterpathfindingcharacters.cpp new file mode 100644 index 000000000..6a7f9fa00 --- /dev/null +++ b/indra/newview/llfloaterpathfindingcharacters.cpp @@ -0,0 +1,309 @@ +/** +* @file llfloaterpathfindingcharacters.cpp +* @brief "Pathfinding characters" floater, allowing for identification of pathfinding characters and their cpu usage. +* @author Stinson@lindenlab.com +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterpathfindingcharacters.h" + +#include + +#include "llcheckboxctrl.h" +#include "llfloaterpathfindingobjects.h" +#include "llhandle.h" +#include "llpathfindingcharacter.h" +#include "llpathfindingcharacterlist.h" +#include "llpathfindingmanager.h" +#include "llpathfindingobject.h" +#include "llpathfindingobjectlist.h" +#include "llpathinglib.h" +#include "llquaternion.h" +#include "llsd.h" +#include "llui.h" +#include "lluictrlfactory.h" +#include "lluuid.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "pipeline.h" +#include "v3math.h" +#include "v4color.h" + +//--------------------------------------------------------------------------- +// LLFloaterPathfindingCharacters +//--------------------------------------------------------------------------- + +void LLFloaterPathfindingCharacters::onClose(bool pIsAppQuitting) +{ + // Hide any capsule that might be showing on floater close + hideCapsule(); + LLFloaterPathfindingObjects::onClose( pIsAppQuitting ); +} + +BOOL LLFloaterPathfindingCharacters::isShowPhysicsCapsule() const +{ + return mShowPhysicsCapsuleCheckBox->get(); +} + +void LLFloaterPathfindingCharacters::setShowPhysicsCapsule(BOOL pIsShowPhysicsCapsule) +{ + mShowPhysicsCapsuleCheckBox->set(pIsShowPhysicsCapsule && (LLPathingLib::getInstance() != NULL)); +} + +BOOL LLFloaterPathfindingCharacters::isPhysicsCapsuleEnabled(LLUUID& id, LLVector3& pos, LLQuaternion& rot) const +{ + id = mSelectedCharacterId; + // Physics capsule is enable if the checkbox is enabled and if we can get the required render + // parameters for any selected object + return (isShowPhysicsCapsule() && getCapsuleRenderData(pos, rot )); +} + +void LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects() +{ + LLFloaterPathfindingCharacters* charactersFloater = getInstance(); + charactersFloater->showFloaterWithSelectionObjects(); +} + +LLFloaterPathfindingCharacters::LLFloaterPathfindingCharacters(const LLSD& pSeed) + : LLFloaterPathfindingObjects(/*pSeed*/), + mShowPhysicsCapsuleCheckBox(NULL), + mSelectedCharacterId(), + mBeaconColor() +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_pathfinding_characters.xml"); +} + +LLFloaterPathfindingCharacters::~LLFloaterPathfindingCharacters() +{ +} + +BOOL LLFloaterPathfindingCharacters::postBuild() +{ + mBeaconColor = LLUI::sColorsGroup->getColor("PathfindingCharacterBeaconColor"); + + mShowPhysicsCapsuleCheckBox = getChild("show_physics_capsule"); + llassert(mShowPhysicsCapsuleCheckBox != NULL); + mShowPhysicsCapsuleCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onShowPhysicsCapsuleClicked, this)); + mShowPhysicsCapsuleCheckBox->setEnabled(LLPathingLib::getInstance() != NULL); + + return LLFloaterPathfindingObjects::postBuild(); +} + +void LLFloaterPathfindingCharacters::requestGetObjects() +{ + LLPathfindingManager::getInstance()->requestGetCharacters(getNewRequestId(), boost::bind(&LLFloaterPathfindingCharacters::handleNewObjectList, this, _1, _2, _3)); +} + +void LLFloaterPathfindingCharacters::buildObjectsScrollList(const LLPathfindingObjectListPtr pObjectListPtr) +{ + llassert(pObjectListPtr != NULL); + llassert(!pObjectListPtr->isEmpty()); + + for (LLPathfindingObjectList::const_iterator objectIter = pObjectListPtr->begin(); objectIter != pObjectListPtr->end(); ++objectIter) + { + const LLPathfindingObjectPtr objectPtr = objectIter->second; + const LLPathfindingCharacter *characterPtr = dynamic_cast(objectPtr.get()); + llassert(characterPtr != NULL); + + LLSD scrollListItemData = buildCharacterScrollListItemData(characterPtr); + addObjectToScrollList(objectPtr, scrollListItemData); + } +} + +void LLFloaterPathfindingCharacters::updateControlsOnScrollListChange() +{ + LLFloaterPathfindingObjects::updateControlsOnScrollListChange(); + updateStateOnDisplayControls(); + showSelectedCharacterCapsules(); +} + +S32 LLFloaterPathfindingCharacters::getNameColumnIndex() const +{ + return 0; +} + +S32 LLFloaterPathfindingCharacters::getOwnerNameColumnIndex() const +{ + return 2; +} + +std::string LLFloaterPathfindingCharacters::getOwnerName(const LLPathfindingObject *pObject) const +{ + return (pObject->hasOwner() + ? (pObject->hasOwnerName() + ? (pObject->isGroupOwned() + ? (pObject->getOwnerName() + " " + getString("character_owner_group")) + : pObject->getOwnerName()) + : getString("character_owner_loading")) + : getString("character_owner_unknown")); +} + +const LLColor4 &LLFloaterPathfindingCharacters::getBeaconColor() const +{ + return mBeaconColor; +} + +LLPathfindingObjectListPtr LLFloaterPathfindingCharacters::getEmptyObjectList() const +{ + LLPathfindingObjectListPtr objectListPtr(new LLPathfindingCharacterList()); + return objectListPtr; +} + +void LLFloaterPathfindingCharacters::onShowPhysicsCapsuleClicked() +{ + if (LLPathingLib::getInstance() == NULL) + { + if (isShowPhysicsCapsule()) + { + setShowPhysicsCapsule(FALSE); + } + } + else + { + if (mSelectedCharacterId.notNull() && isShowPhysicsCapsule()) + { + showCapsule(); + } + else + { + hideCapsule(); + } + } +} + +LLSD LLFloaterPathfindingCharacters::buildCharacterScrollListItemData(const LLPathfindingCharacter *pCharacterPtr) const +{ + LLSD columns = LLSD::emptyArray(); + + columns[0]["column"] = "name"; + columns[0]["value"] = pCharacterPtr->getName(); + + columns[1]["column"] = "description"; + columns[1]["value"] = pCharacterPtr->getDescription(); + + columns[2]["column"] = "owner"; + columns[2]["value"] = getOwnerName(pCharacterPtr); + + S32 cpuTime = llround(pCharacterPtr->getCPUTime()); + std::string cpuTimeString = llformat("%d", cpuTime); + LLStringUtil::format_map_t string_args; + string_args["[CPU_TIME]"] = cpuTimeString; + + columns[3]["column"] = "cpu_time"; + columns[3]["value"] = getString("character_cpu_time", string_args); + + columns[4]["column"] = "altitude"; + columns[4]["value"] = llformat("%1.0f m", pCharacterPtr->getLocation()[2]); + + return columns; +} + +void LLFloaterPathfindingCharacters::updateStateOnDisplayControls() +{ + int numSelectedItems = getNumSelectedObjects();; + bool isEditEnabled = ((numSelectedItems == 1) && (LLPathingLib::getInstance() != NULL)); + + mShowPhysicsCapsuleCheckBox->setEnabled(isEditEnabled); + if (!isEditEnabled) + { + setShowPhysicsCapsule(FALSE); + } +} + +void LLFloaterPathfindingCharacters::showSelectedCharacterCapsules() +{ + // Hide any previous capsule + hideCapsule(); + + // Get the only selected object, or set the selected object to null if we do not have exactly + // one object selected + if (getNumSelectedObjects() == 1) + { + LLPathfindingObjectPtr selectedObjectPtr = getFirstSelectedObject(); + mSelectedCharacterId = selectedObjectPtr->getUUID(); + } + else + { + mSelectedCharacterId.setNull(); + } + + // Show any capsule if enabled + showCapsule(); +} + +void LLFloaterPathfindingCharacters::showCapsule() const +{ + if (mSelectedCharacterId.notNull() && isShowPhysicsCapsule()) + { + LLPathfindingObjectPtr objectPtr = getFirstSelectedObject(); + llassert(objectPtr != NULL); + if (objectPtr != NULL) + { + const LLPathfindingCharacter *character = dynamic_cast(objectPtr.get()); + llassert(mSelectedCharacterId == character->getUUID()); + if (LLPathingLib::getInstance() != NULL) + { + LLPathingLib::getInstance()->createPhysicsCapsuleRep(character->getLength(), character->getRadius(), + character->isHorizontal(), character->getUUID()); + } + } + + gPipeline.hideObject(mSelectedCharacterId); + } +} + +void LLFloaterPathfindingCharacters::hideCapsule() const +{ + if (mSelectedCharacterId.notNull()) + { + gPipeline.restoreHiddenObject(mSelectedCharacterId); + } + if (LLPathingLib::getInstance() != NULL) + { + LLPathingLib::getInstance()->cleanupPhysicsCapsuleRepResiduals(); + } +} + +bool LLFloaterPathfindingCharacters::getCapsuleRenderData(LLVector3& pPosition, LLQuaternion& rot) const +{ + bool result = false; + + // If we have a selected object, find the object on the viewer object list and return its + // position. Else, return false indicating that we either do not have a selected object + // or we cannot find the selected object on the viewer object list + if (mSelectedCharacterId.notNull()) + { + LLViewerObject *viewerObject = gObjectList.findObject(mSelectedCharacterId); + if ( viewerObject != NULL ) + { + rot = viewerObject->getRotation() ; + pPosition = viewerObject->getRenderPosition(); + result = true; + } + } + + return result; +} diff --git a/indra/newview/llfloaterpathfindingcharacters.h b/indra/newview/llfloaterpathfindingcharacters.h new file mode 100644 index 000000000..70036219d --- /dev/null +++ b/indra/newview/llfloaterpathfindingcharacters.h @@ -0,0 +1,94 @@ +/** +* @file llfloaterpathfindingcharacters.h +* @brief "Pathfinding characters" floater, allowing for identification of pathfinding characters and their cpu usage. +* @author Stinson@lindenlab.com +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLFLOATERPATHFINDINGCHARACTERS_H +#define LL_LLFLOATERPATHFINDINGCHARACTERS_H + +#include "llfloaterpathfindingobjects.h" +#include "llpathfindingobjectlist.h" +#include "lluuid.h" +#include "v4color.h" + +class LLCheckBoxCtrl; +class LLPathfindingCharacter; +class LLQuaternion; +class LLSD; +class LLVector3; + +class LLFloaterPathfindingCharacters : public LLFloaterPathfindingObjects, public LLFloaterSingleton +{ +public: + virtual void onClose(bool pIsAppQuitting); + + BOOL isShowPhysicsCapsule() const; + void setShowPhysicsCapsule(BOOL pIsShowPhysicsCapsule); + + BOOL isPhysicsCapsuleEnabled(LLUUID& id, LLVector3& pos, LLQuaternion& rot) const; + + static void openCharactersWithSelectedObjects(); + + LLFloaterPathfindingCharacters(const LLSD& pSeed); + virtual ~LLFloaterPathfindingCharacters(); + +protected: +// friend class LLFloaterReg; + + virtual BOOL postBuild(); + + virtual void requestGetObjects(); + + virtual void buildObjectsScrollList(const LLPathfindingObjectListPtr pObjectListPtr); + + virtual void updateControlsOnScrollListChange(); + + virtual S32 getNameColumnIndex() const; + virtual S32 getOwnerNameColumnIndex() const; + virtual std::string getOwnerName(const LLPathfindingObject *pObject) const; + virtual const LLColor4 &getBeaconColor() const; + + virtual LLPathfindingObjectListPtr getEmptyObjectList() const; + +private: + void onShowPhysicsCapsuleClicked(); + + LLSD buildCharacterScrollListItemData(const LLPathfindingCharacter *pCharacterPtr) const; + + void updateStateOnDisplayControls(); + void showSelectedCharacterCapsules(); + + void showCapsule() const; + void hideCapsule() const; + + bool getCapsuleRenderData(LLVector3& pPosition, LLQuaternion& rot) const; + + LLCheckBoxCtrl *mShowPhysicsCapsuleCheckBox; + + LLUUID mSelectedCharacterId; + + LLColor4 mBeaconColor; +}; + +#endif // LL_LLFLOATERPATHFINDINGCHARACTERS_H diff --git a/indra/newview/llfloaterpathfindinglinksets.cpp b/indra/newview/llfloaterpathfindinglinksets.cpp new file mode 100644 index 000000000..69b4bce60 --- /dev/null +++ b/indra/newview/llfloaterpathfindinglinksets.cpp @@ -0,0 +1,806 @@ +/** +* @file llfloaterpathfindinglinksets.cpp +* @brief "Pathfinding linksets" floater, allowing manipulation of the linksets on the current region. +* @author Stinson@lindenlab.com +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterpathfindinglinksets.h" + +#include + +#include + +#include "llagent.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "llfloaterpathfindingobjects.h" +#include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llpathfindinglinkset.h" +#include "llpathfindinglinksetlist.h" +#include "llpathfindingmanager.h" +#include "llscrolllistctrl.h" +#include "llsd.h" +#include "lltextbox.h" +#include "llui.h" +#include "lluictrlfactory.h" +#include "lluictrl.h" +#include "v3math.h" +#include "v4color.h" + +#define XUI_LINKSET_USE_NONE 0 +#define XUI_LINKSET_USE_WALKABLE 1 +#define XUI_LINKSET_USE_STATIC_OBSTACLE 2 +#define XUI_LINKSET_USE_DYNAMIC_OBSTACLE 3 +#define XUI_LINKSET_USE_MATERIAL_VOLUME 4 +#define XUI_LINKSET_USE_EXCLUSION_VOLUME 5 +#define XUI_LINKSET_USE_DYNAMIC_PHANTOM 6 + +//--------------------------------------------------------------------------- +// LLFloaterPathfindingLinksets +//--------------------------------------------------------------------------- + +void LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects() +{ + LLFloaterPathfindingLinksets* linksetsFloater = getInstance(); + linksetsFloater->clearFilters(); + linksetsFloater->showFloaterWithSelectionObjects(); +} + +LLFloaterPathfindingLinksets::LLFloaterPathfindingLinksets(const LLSD& pSeed) + : LLFloaterPathfindingObjects(/*pSeed*/), + mFilterByName(NULL), + mFilterByDescription(NULL), + mFilterByLinksetUse(NULL), + mEditLinksetUse(NULL), + mEditLinksetUseWalkable(NULL), + mEditLinksetUseStaticObstacle(NULL), + mEditLinksetUseDynamicObstacle(NULL), + mEditLinksetUseMaterialVolume(NULL), + mEditLinksetUseExclusionVolume(NULL), + mEditLinksetUseDynamicPhantom(NULL), + mLabelWalkabilityCoefficients(NULL), + mLabelEditA(NULL), + mLabelSuggestedUseA(NULL), + mEditA(NULL), + mLabelEditB(NULL), + mLabelSuggestedUseB(NULL), + mEditB(NULL), + mLabelEditC(NULL), + mLabelSuggestedUseC(NULL), + mEditC(NULL), + mLabelEditD(NULL), + mLabelSuggestedUseD(NULL), + mEditD(NULL), + mApplyEditsButton(NULL), + mBeaconColor(), + mPreviousValueA(LLPathfindingLinkset::MAX_WALKABILITY_VALUE), + mPreviousValueB(LLPathfindingLinkset::MAX_WALKABILITY_VALUE), + mPreviousValueC(LLPathfindingLinkset::MAX_WALKABILITY_VALUE), + mPreviousValueD(LLPathfindingLinkset::MAX_WALKABILITY_VALUE) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_pathfinding_linksets.xml"); +} + +LLFloaterPathfindingLinksets::~LLFloaterPathfindingLinksets() +{ +} + +BOOL LLFloaterPathfindingLinksets::postBuild() +{ + mBeaconColor = LLUI::sColorsGroup->getColor("PathfindingLinksetBeaconColor"); + + mFilterByName = getChild("filter_by_name"); + llassert(mFilterByName != NULL); + mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); + mFilterByName->setSelectAllonFocusReceived(true); + mFilterByName->setCommitOnFocusLost(true); + + mFilterByDescription = getChild("filter_by_description"); + llassert(mFilterByDescription != NULL); + mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); + mFilterByDescription->setSelectAllonFocusReceived(true); + mFilterByDescription->setCommitOnFocusLost(true); + + mFilterByLinksetUse = getChild("filter_by_linkset_use"); + llassert(mFilterByLinksetUse != NULL); + mFilterByLinksetUse->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); + + childSetAction("apply_filters", boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); + childSetAction("clear_filters", boost::bind(&LLFloaterPathfindingLinksets::onClearFiltersClicked, this)); + + mEditLinksetUse = getChild("edit_linkset_use"); + llassert(mEditLinksetUse != NULL); + mEditLinksetUse->clearRows(); + + mEditLinksetUseUnset = mEditLinksetUse->add(getString("linkset_choose_use"), XUI_LINKSET_USE_NONE); + llassert(mEditLinksetUseUnset != NULL); + + mEditLinksetUseWalkable = mEditLinksetUse->add(getLinksetUseString(LLPathfindingLinkset::kWalkable), XUI_LINKSET_USE_WALKABLE); + llassert(mEditLinksetUseWalkable != NULL); + + mEditLinksetUseStaticObstacle = mEditLinksetUse->add(getLinksetUseString(LLPathfindingLinkset::kStaticObstacle), XUI_LINKSET_USE_STATIC_OBSTACLE); + llassert(mEditLinksetUseStaticObstacle != NULL); + + mEditLinksetUseDynamicObstacle = mEditLinksetUse->add(getLinksetUseString(LLPathfindingLinkset::kDynamicObstacle), XUI_LINKSET_USE_DYNAMIC_OBSTACLE); + llassert(mEditLinksetUseDynamicObstacle != NULL); + + mEditLinksetUseMaterialVolume = mEditLinksetUse->add(getLinksetUseString(LLPathfindingLinkset::kMaterialVolume), XUI_LINKSET_USE_MATERIAL_VOLUME); + llassert(mEditLinksetUseMaterialVolume != NULL); + + mEditLinksetUseExclusionVolume = mEditLinksetUse->add(getLinksetUseString(LLPathfindingLinkset::kExclusionVolume), XUI_LINKSET_USE_EXCLUSION_VOLUME); + llassert(mEditLinksetUseExclusionVolume != NULL); + + mEditLinksetUseDynamicPhantom = mEditLinksetUse->add(getLinksetUseString(LLPathfindingLinkset::kDynamicPhantom), XUI_LINKSET_USE_DYNAMIC_PHANTOM); + llassert(mEditLinksetUseDynamicPhantom != NULL); + + mEditLinksetUse->selectFirstItem(); + + mLabelWalkabilityCoefficients = getChild("walkability_coefficients_label"); + llassert(mLabelWalkabilityCoefficients != NULL); + + mLabelEditA = getChild("edit_a_label"); + llassert(mLabelEditA != NULL); + + mLabelSuggestedUseA = getChild("suggested_use_a_label"); + llassert(mLabelSuggestedUseA != NULL); + + mEditA = getChild("edit_a_value"); + llassert(mEditA != NULL); + mEditA->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32); + mEditA->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1, mPreviousValueA)); + + mLabelEditB = getChild("edit_b_label"); + llassert(mLabelEditB != NULL); + + mLabelSuggestedUseB = getChild("suggested_use_b_label"); + llassert(mLabelSuggestedUseB != NULL); + + mEditB = getChild("edit_b_value"); + llassert(mEditB != NULL); + mEditB->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32); + mEditB->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1, mPreviousValueB)); + + mLabelEditC = getChild("edit_c_label"); + llassert(mLabelEditC != NULL); + + mLabelSuggestedUseC = getChild("suggested_use_c_label"); + llassert(mLabelSuggestedUseC != NULL); + + mEditC = getChild("edit_c_value"); + llassert(mEditC != NULL); + mEditC->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32); + mEditC->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1, mPreviousValueC)); + + mLabelEditD = getChild("edit_d_label"); + llassert(mLabelEditD != NULL); + + mLabelSuggestedUseD = getChild("suggested_use_d_label"); + llassert(mLabelSuggestedUseD != NULL); + + mEditD = getChild("edit_d_value"); + llassert(mEditD != NULL); + mEditD->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32); + mEditD->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1, mPreviousValueD)); + + mApplyEditsButton = getChild("apply_edit_values"); + llassert(mApplyEditsButton != NULL); + mApplyEditsButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyChangesClicked, this)); + + return LLFloaterPathfindingObjects::postBuild(); +} + +void LLFloaterPathfindingLinksets::requestGetObjects() +{ + LLPathfindingManager::getInstance()->requestGetLinksets(getNewRequestId(), boost::bind(&LLFloaterPathfindingLinksets::handleNewObjectList, this, _1, _2, _3)); +} + +void LLFloaterPathfindingLinksets::buildObjectsScrollList(const LLPathfindingObjectListPtr pObjectListPtr) +{ + llassert(pObjectListPtr != NULL); + llassert(!pObjectListPtr->isEmpty()); + + std::string nameFilter = mFilterByName->getText(); + std::string descriptionFilter = mFilterByDescription->getText(); + LLPathfindingLinkset::ELinksetUse linksetUseFilter = getFilterLinksetUse(); + bool isFilteringName = !nameFilter.empty(); + bool isFilteringDescription = !descriptionFilter.empty(); + bool isFilteringLinksetUse = (linksetUseFilter != LLPathfindingLinkset::kUnknown); + + const LLVector3& avatarPosition = gAgent.getPositionAgent(); + + if (isFilteringName || isFilteringDescription || isFilteringLinksetUse) + { + LLStringUtil::toUpper(nameFilter); + LLStringUtil::toUpper(descriptionFilter); + for (LLPathfindingObjectList::const_iterator objectIter = pObjectListPtr->begin(); objectIter != pObjectListPtr->end(); ++objectIter) + { + const LLPathfindingObjectPtr objectPtr = objectIter->second; + const LLPathfindingLinkset *linksetPtr = dynamic_cast(objectPtr.get()); + llassert(linksetPtr != NULL); + + std::string linksetName = (linksetPtr->isTerrain() ? getString("linkset_terrain_name") : linksetPtr->getName()); + std::string linksetDescription = linksetPtr->getDescription(); + LLStringUtil::toUpper(linksetName); + LLStringUtil::toUpper(linksetDescription); + + if ((!isFilteringName || (linksetName.find(nameFilter) != std::string::npos)) && + (!isFilteringDescription || (linksetDescription.find(descriptionFilter) != std::string::npos)) && + (!isFilteringLinksetUse || (linksetPtr->getLinksetUse() == linksetUseFilter))) + { + LLSD scrollListItemData = buildLinksetScrollListItemData(linksetPtr, avatarPosition); + addObjectToScrollList(objectPtr, scrollListItemData); + } + } + } + else + { + for (LLPathfindingObjectList::const_iterator objectIter = pObjectListPtr->begin(); objectIter != pObjectListPtr->end(); ++objectIter) + { + const LLPathfindingObjectPtr objectPtr = objectIter->second; + const LLPathfindingLinkset *linksetPtr = dynamic_cast(objectPtr.get()); + llassert(linksetPtr != NULL); + + LLSD scrollListItemData = buildLinksetScrollListItemData(linksetPtr, avatarPosition); + addObjectToScrollList(objectPtr, scrollListItemData); + } + } +} + +void LLFloaterPathfindingLinksets::updateControlsOnScrollListChange() +{ + LLFloaterPathfindingObjects::updateControlsOnScrollListChange(); + updateEditFieldValues(); + updateStateOnEditFields(); + updateStateOnEditLinksetUse(); +} + +S32 LLFloaterPathfindingLinksets::getNameColumnIndex() const +{ + return 0; +} + +S32 LLFloaterPathfindingLinksets::getOwnerNameColumnIndex() const +{ + return 2; +} + +std::string LLFloaterPathfindingLinksets::getOwnerName(const LLPathfindingObject *pObject) const +{ + return (pObject->hasOwner() + ? (pObject->hasOwnerName() + ? (pObject->isGroupOwned() + ? (pObject->getOwnerName() + " " + getString("linkset_owner_group")) + : pObject->getOwnerName()) + : getString("linkset_owner_loading")) + : getString("linkset_owner_unknown")); +} + +const LLColor4 &LLFloaterPathfindingLinksets::getBeaconColor() const +{ + return mBeaconColor; +} + +LLPathfindingObjectListPtr LLFloaterPathfindingLinksets::getEmptyObjectList() const +{ + LLPathfindingObjectListPtr objectListPtr(new LLPathfindingLinksetList()); + return objectListPtr; +} + +void LLFloaterPathfindingLinksets::requestSetLinksets(LLPathfindingObjectListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) +{ + LLPathfindingManager::getInstance()->requestSetLinksets(getNewRequestId(), pLinksetList, pLinksetUse, pA, pB, pC, pD, boost::bind(&LLFloaterPathfindingLinksets::handleUpdateObjectList, this, _1, _2, _3)); +} + +void LLFloaterPathfindingLinksets::onApplyAllFilters() +{ + rebuildObjectsScrollList(); +} + +void LLFloaterPathfindingLinksets::onClearFiltersClicked() +{ + clearFilters(); + rebuildObjectsScrollList(); +} + +void LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered(LLUICtrl *pUICtrl, LLSD &pPreviousValue) +{ + LLLineEditor *pLineEditor = static_cast(pUICtrl); + llassert(pLineEditor != NULL); + + const std::string &valueString = pLineEditor->getText(); + + S32 intValue; + LLSD value; + bool doResetValue = false; + + if (valueString.empty()) + { + value = pPreviousValue; + doResetValue = true; + } + else if (LLStringUtil::convertToS32(valueString, intValue)) + { + doResetValue = ((intValue < LLPathfindingLinkset::MIN_WALKABILITY_VALUE) || (intValue > LLPathfindingLinkset::MAX_WALKABILITY_VALUE)); + value = LLSD(llclamp(intValue, LLPathfindingLinkset::MIN_WALKABILITY_VALUE, LLPathfindingLinkset::MAX_WALKABILITY_VALUE)); + } + else + { + value = LLSD(LLPathfindingLinkset::MAX_WALKABILITY_VALUE); + doResetValue = true; + } + + if (doResetValue) + { + pLineEditor->setValue(value); + } + pPreviousValue = value; +} + +void LLFloaterPathfindingLinksets::onApplyChangesClicked() +{ + applyEdit(); +} + +void LLFloaterPathfindingLinksets::clearFilters() +{ + mFilterByName->clear(); + mFilterByDescription->clear(); + setFilterLinksetUse(LLPathfindingLinkset::kUnknown); +} + +void LLFloaterPathfindingLinksets::updateEditFieldValues() +{ + int numSelectedObjects = getNumSelectedObjects(); + if (numSelectedObjects <= 0) + { + mEditLinksetUse->selectFirstItem(); + mEditA->clear(); + mEditB->clear(); + mEditC->clear(); + mEditD->clear(); + } + else + { + LLPathfindingObjectPtr firstSelectedObjectPtr = getFirstSelectedObject(); + llassert(firstSelectedObjectPtr != NULL); + + const LLPathfindingLinkset *linkset = dynamic_cast(firstSelectedObjectPtr.get()); + + setEditLinksetUse(linkset->getLinksetUse()); + mPreviousValueA = LLSD(linkset->getWalkabilityCoefficientA()); + mPreviousValueB = LLSD(linkset->getWalkabilityCoefficientB()); + mPreviousValueC = LLSD(linkset->getWalkabilityCoefficientC()); + mPreviousValueD = LLSD(linkset->getWalkabilityCoefficientD()); + mEditA->setValue(mPreviousValueA); + mEditB->setValue(mPreviousValueB); + mEditC->setValue(mPreviousValueC); + mEditD->setValue(mPreviousValueD); + } +} + +LLSD LLFloaterPathfindingLinksets::buildLinksetScrollListItemData(const LLPathfindingLinkset *pLinksetPtr, const LLVector3 &pAvatarPosition) const +{ + llassert(pLinksetPtr != NULL); + LLSD columns = LLSD::emptyArray(); + + if (pLinksetPtr->isTerrain()) + { + columns[0]["column"] = "name"; + columns[0]["value"] = getString("linkset_terrain_name"); + + columns[1]["column"] = "description"; + columns[1]["value"] = getString("linkset_terrain_description"); + + columns[2]["column"] = "owner"; + columns[2]["value"] = getString("linkset_terrain_owner"); + + columns[3]["column"] = "scripted"; + columns[3]["value"] = getString("linkset_terrain_scripted"); + + columns[4]["column"] = "land_impact"; + columns[4]["value"] = getString("linkset_terrain_land_impact"); + + columns[5]["column"] = "dist_from_you"; + columns[5]["value"] = getString("linkset_terrain_dist_from_you"); + } + else + { + columns[0]["column"] = "name"; + columns[0]["value"] = pLinksetPtr->getName(); + + columns[1]["column"] = "description"; + columns[1]["value"] = pLinksetPtr->getDescription(); + + columns[2]["column"] = "owner"; + columns[2]["value"] = getOwnerName(pLinksetPtr); + + columns[3]["column"] = "scripted"; + columns[3]["value"] = (pLinksetPtr->hasIsScripted() + ? (pLinksetPtr->isScripted() + ? getString("linkset_is_scripted") + : getString("linkset_is_not_scripted")) + : getString("linkset_is_unknown_scripted")); + + columns[4]["column"] = "land_impact"; + columns[4]["value"] = llformat("%1d", pLinksetPtr->getLandImpact()); + + columns[5]["column"] = "dist_from_you"; + columns[5]["value"] = llformat("%1.0f m", dist_vec(pAvatarPosition, pLinksetPtr->getLocation())); + } + + columns[6]["column"] = "linkset_use"; + std::string linksetUse = getLinksetUseString(pLinksetPtr->getLinksetUse()); + if (pLinksetPtr->isTerrain()) + { + linksetUse += (" " + getString("linkset_is_terrain")); + } + else if (!pLinksetPtr->isModifiable() && pLinksetPtr->canBeVolume()) + { + linksetUse += (" " + getString("linkset_is_restricted_state")); + } + else if (pLinksetPtr->isModifiable() && !pLinksetPtr->canBeVolume()) + { + linksetUse += (" " + getString("linkset_is_non_volume_state")); + } + else if (!pLinksetPtr->isModifiable() && !pLinksetPtr->canBeVolume()) + { + linksetUse += (" " + getString("linkset_is_restricted_non_volume_state")); + } + columns[6]["value"] = linksetUse; + + columns[7]["column"] = "a_percent"; + columns[7]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientA()); + + columns[8]["column"] = "b_percent"; + columns[8]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientB()); + + columns[9]["column"] = "c_percent"; + columns[9]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientC()); + + columns[10]["column"] = "d_percent"; + columns[10]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientD()); + + return columns; +} + +/* Singu-Note: Unused function +LLSD LLFloaterPathfindingLinksets::buildLinksetUseScrollListData(const std::string &pLabel, S32 pValue) const +{ + LLSD columns; + + columns[0]["column"] = "name"; + columns[0]["value"] = pLabel; + columns[0]["font"] = "SANSSERIF"; + + LLSD element; + element["value"] = pValue; + element["column"] = columns; + + return element; +} +*/ + +bool LLFloaterPathfindingLinksets::isShowUnmodifiablePhantomWarning(LLPathfindingLinkset::ELinksetUse pLinksetUse) const +{ + bool isShowWarning = false; + + if (pLinksetUse != LLPathfindingLinkset::kUnknown) + { + LLPathfindingObjectListPtr selectedObjects = getSelectedObjects(); + if ((selectedObjects != NULL) && !selectedObjects->isEmpty()) + { + const LLPathfindingLinksetList *linksetList = dynamic_cast(selectedObjects.get()); + isShowWarning = linksetList->isShowUnmodifiablePhantomWarning(pLinksetUse); + } + } + + return isShowWarning; +} + +bool LLFloaterPathfindingLinksets::isShowPhantomToggleWarning(LLPathfindingLinkset::ELinksetUse pLinksetUse) const +{ + bool isShowWarning = false; + + if (pLinksetUse != LLPathfindingLinkset::kUnknown) + { + LLPathfindingObjectListPtr selectedObjects = getSelectedObjects(); + if ((selectedObjects != NULL) && !selectedObjects->isEmpty()) + { + const LLPathfindingLinksetList *linksetList = dynamic_cast(selectedObjects.get()); + isShowWarning = linksetList->isShowPhantomToggleWarning(pLinksetUse); + } + } + + return isShowWarning; +} + +bool LLFloaterPathfindingLinksets::isShowCannotBeVolumeWarning(LLPathfindingLinkset::ELinksetUse pLinksetUse) const +{ + bool isShowWarning = false; + + if (pLinksetUse != LLPathfindingLinkset::kUnknown) + { + LLPathfindingObjectListPtr selectedObjects = getSelectedObjects(); + if ((selectedObjects != NULL) && !selectedObjects->isEmpty()) + { + const LLPathfindingLinksetList *linksetList = dynamic_cast(selectedObjects.get()); + isShowWarning = linksetList->isShowCannotBeVolumeWarning(pLinksetUse); + } + } + + return isShowWarning; +} + +void LLFloaterPathfindingLinksets::updateStateOnEditFields() +{ + int numSelectedItems = getNumSelectedObjects(); + bool isEditEnabled = (numSelectedItems > 0); + + mEditLinksetUse->setEnabled(isEditEnabled); + + mLabelWalkabilityCoefficients->setEnabled(isEditEnabled); + mLabelEditA->setEnabled(isEditEnabled); + mLabelEditB->setEnabled(isEditEnabled); + mLabelEditC->setEnabled(isEditEnabled); + mLabelEditD->setEnabled(isEditEnabled); + mLabelSuggestedUseA->setEnabled(isEditEnabled); + mLabelSuggestedUseB->setEnabled(isEditEnabled); + mLabelSuggestedUseC->setEnabled(isEditEnabled); + mLabelSuggestedUseD->setEnabled(isEditEnabled); + mEditA->setEnabled(isEditEnabled); + mEditB->setEnabled(isEditEnabled); + mEditC->setEnabled(isEditEnabled); + mEditD->setEnabled(isEditEnabled); + + mApplyEditsButton->setEnabled(isEditEnabled && (getMessagingState() == kMessagingComplete)); +} + +void LLFloaterPathfindingLinksets::updateStateOnEditLinksetUse() +{ + BOOL useWalkable = FALSE; + BOOL useStaticObstacle = FALSE; + BOOL useDynamicObstacle = FALSE; + BOOL useMaterialVolume = FALSE; + BOOL useExclusionVolume = FALSE; + BOOL useDynamicPhantom = FALSE; + + LLPathfindingObjectListPtr selectedObjects = getSelectedObjects(); + if ((selectedObjects != NULL) && !selectedObjects->isEmpty()) + { + const LLPathfindingLinksetList *linksetList = dynamic_cast(selectedObjects.get()); + linksetList->determinePossibleStates(useWalkable, useStaticObstacle, useDynamicObstacle, useMaterialVolume, useExclusionVolume, useDynamicPhantom); + } + + mEditLinksetUseWalkable->setEnabled(useWalkable); + mEditLinksetUseStaticObstacle->setEnabled(useStaticObstacle); + mEditLinksetUseDynamicObstacle->setEnabled(useDynamicObstacle); + mEditLinksetUseMaterialVolume->setEnabled(useMaterialVolume); + mEditLinksetUseExclusionVolume->setEnabled(useExclusionVolume); + mEditLinksetUseDynamicPhantom->setEnabled(useDynamicPhantom); +} + +void LLFloaterPathfindingLinksets::applyEdit() +{ + LLPathfindingLinkset::ELinksetUse linksetUse = getEditLinksetUse(); + + bool showPhantomToggleWarning = isShowPhantomToggleWarning(linksetUse); + bool showUnmodifiablePhantomWarning = isShowUnmodifiablePhantomWarning(linksetUse); + bool showCannotBeVolumeWarning = isShowCannotBeVolumeWarning(linksetUse); + + if (showPhantomToggleWarning || showUnmodifiablePhantomWarning || showCannotBeVolumeWarning) + { + LLPathfindingLinkset::ELinksetUse restrictedLinksetUse = LLPathfindingLinkset::getLinksetUseWithToggledPhantom(linksetUse); + LLSD substitutions; + substitutions["REQUESTED_TYPE"] = getLinksetUseString(linksetUse); + substitutions["RESTRICTED_TYPE"] = getLinksetUseString(restrictedLinksetUse); + + // Build one of the following notifications names + // - PathfindingLinksets_WarnOnPhantom + // - PathfindingLinksets_WarnOnPhantom_MismatchOnRestricted + // - PathfindingLinksets_WarnOnPhantom_MismatchOnVolume + // - PathfindingLinksets_WarnOnPhantom_MismatchOnRestricted_MismatchOnVolume + // - PathfindingLinksets_MismatchOnRestricted + // - PathfindingLinksets_MismatchOnVolume + // - PathfindingLinksets_MismatchOnRestricted_MismatchOnVolume + + std::string notificationName = "PathfindingLinksets"; + + if (showPhantomToggleWarning) + { + notificationName += "_WarnOnPhantom"; + } + if (showUnmodifiablePhantomWarning) + { + notificationName += "_MismatchOnRestricted"; + } + if (showCannotBeVolumeWarning) + { + notificationName += "_MismatchOnVolume"; + } + + LLNotificationsUtil::add(notificationName, substitutions, LLSD(), boost::bind(&LLFloaterPathfindingLinksets::handleApplyEdit, this, _1, _2)); + } + else + { + doApplyEdit(); + } +} + +void LLFloaterPathfindingLinksets::handleApplyEdit(const LLSD &pNotification, const LLSD &pResponse) +{ + if (LLNotificationsUtil::getSelectedOption(pNotification, pResponse) == 0) + { + doApplyEdit(); + } +} + +void LLFloaterPathfindingLinksets::doApplyEdit() +{ + LLPathfindingObjectListPtr selectedObjects = getSelectedObjects(); + if ((selectedObjects != NULL) && !selectedObjects->isEmpty()) + { + LLPathfindingLinkset::ELinksetUse linksetUse = getEditLinksetUse(); + const std::string &aString = mEditA->getText(); + const std::string &bString = mEditB->getText(); + const std::string &cString = mEditC->getText(); + const std::string &dString = mEditD->getText(); + S32 aValue = static_cast(atoi(aString.c_str())); + S32 bValue = static_cast(atoi(bString.c_str())); + S32 cValue = static_cast(atoi(cString.c_str())); + S32 dValue = static_cast(atoi(dString.c_str())); + + + requestSetLinksets(selectedObjects, linksetUse, aValue, bValue, cValue, dValue); + } +} + +std::string LLFloaterPathfindingLinksets::getLinksetUseString(LLPathfindingLinkset::ELinksetUse pLinksetUse) const +{ + std::string linksetUse; + + switch (pLinksetUse) + { + case LLPathfindingLinkset::kWalkable : + linksetUse = getString("linkset_use_walkable"); + break; + case LLPathfindingLinkset::kStaticObstacle : + linksetUse = getString("linkset_use_static_obstacle"); + break; + case LLPathfindingLinkset::kDynamicObstacle : + linksetUse = getString("linkset_use_dynamic_obstacle"); + break; + case LLPathfindingLinkset::kMaterialVolume : + linksetUse = getString("linkset_use_material_volume"); + break; + case LLPathfindingLinkset::kExclusionVolume : + linksetUse = getString("linkset_use_exclusion_volume"); + break; + case LLPathfindingLinkset::kDynamicPhantom : + linksetUse = getString("linkset_use_dynamic_phantom"); + break; + case LLPathfindingLinkset::kUnknown : + default : + linksetUse = getString("linkset_use_dynamic_obstacle"); + llassert(0); + break; + } + + return linksetUse; +} + +LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::getFilterLinksetUse() const +{ + return convertToLinksetUse(mFilterByLinksetUse->getValue()); +} + +void LLFloaterPathfindingLinksets::setFilterLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse) +{ + mFilterByLinksetUse->setValue(convertToXuiValue(pLinksetUse)); +} + +LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::getEditLinksetUse() const +{ + return convertToLinksetUse(mEditLinksetUse->getValue()); +} + +void LLFloaterPathfindingLinksets::setEditLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse) +{ + mEditLinksetUse->setValue(convertToXuiValue(pLinksetUse)); +} + +LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::convertToLinksetUse(LLSD pXuiValue) const +{ + LLPathfindingLinkset::ELinksetUse linkUse; + + switch (pXuiValue.asInteger()) + { + case XUI_LINKSET_USE_NONE : + linkUse = LLPathfindingLinkset::kUnknown; + break; + case XUI_LINKSET_USE_WALKABLE : + linkUse = LLPathfindingLinkset::kWalkable; + break; + case XUI_LINKSET_USE_STATIC_OBSTACLE : + linkUse = LLPathfindingLinkset::kStaticObstacle; + break; + case XUI_LINKSET_USE_DYNAMIC_OBSTACLE : + linkUse = LLPathfindingLinkset::kDynamicObstacle; + break; + case XUI_LINKSET_USE_MATERIAL_VOLUME : + linkUse = LLPathfindingLinkset::kMaterialVolume; + break; + case XUI_LINKSET_USE_EXCLUSION_VOLUME : + linkUse = LLPathfindingLinkset::kExclusionVolume; + break; + case XUI_LINKSET_USE_DYNAMIC_PHANTOM : + linkUse = LLPathfindingLinkset::kDynamicPhantom; + break; + default : + linkUse = LLPathfindingLinkset::kUnknown; + llassert(0); + break; + } + + return linkUse; +} + +LLSD LLFloaterPathfindingLinksets::convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const +{ + LLSD xuiValue; + + switch (pLinksetUse) + { + case LLPathfindingLinkset::kUnknown : + xuiValue = XUI_LINKSET_USE_NONE; + break; + case LLPathfindingLinkset::kWalkable : + xuiValue = XUI_LINKSET_USE_WALKABLE; + break; + case LLPathfindingLinkset::kStaticObstacle : + xuiValue = XUI_LINKSET_USE_STATIC_OBSTACLE; + break; + case LLPathfindingLinkset::kDynamicObstacle : + xuiValue = XUI_LINKSET_USE_DYNAMIC_OBSTACLE; + break; + case LLPathfindingLinkset::kMaterialVolume : + xuiValue = XUI_LINKSET_USE_MATERIAL_VOLUME; + break; + case LLPathfindingLinkset::kExclusionVolume : + xuiValue = XUI_LINKSET_USE_EXCLUSION_VOLUME; + break; + case LLPathfindingLinkset::kDynamicPhantom : + xuiValue = XUI_LINKSET_USE_DYNAMIC_PHANTOM; + break; + default : + xuiValue = XUI_LINKSET_USE_NONE; + llassert(0); + break; + } + + return xuiValue; +} diff --git a/indra/newview/llfloaterpathfindinglinksets.h b/indra/newview/llfloaterpathfindinglinksets.h new file mode 100644 index 000000000..519ce8294 --- /dev/null +++ b/indra/newview/llfloaterpathfindinglinksets.h @@ -0,0 +1,142 @@ +/** +* @file llfloaterpathfindinglinksets.h +* @brief "Pathfinding linksets" floater, allowing manipulation of the linksets on the current region. +* @author Stinson@lindenlab.com +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLFLOATERPATHFINDINGLINKSETS_H +#define LL_LLFLOATERPATHFINDINGLINKSETS_H + +#include + +#include "llfloaterpathfindingobjects.h" +#include "llpathfindinglinkset.h" +#include "llpathfindingobjectlist.h" +#include "v4color.h" + +class LLButton; +class LLComboBox; +class LLLineEditor; +class LLScrollListItem; +class LLSD; +class LLTextBox; +class LLUICtrl; +class LLVector3; + +class LLFloaterPathfindingLinksets : public LLFloaterPathfindingObjects, public LLFloaterSingleton +{ +public: + static void openLinksetsWithSelectedObjects(); + + LLFloaterPathfindingLinksets(const LLSD& pSeed); + virtual ~LLFloaterPathfindingLinksets(); + +protected: +// friend class LLFloaterReg; + + virtual BOOL postBuild(); + + virtual void requestGetObjects(); + + virtual void buildObjectsScrollList(const LLPathfindingObjectListPtr pObjectListPtr); + + virtual void updateControlsOnScrollListChange(); + + virtual S32 getNameColumnIndex() const; + virtual S32 getOwnerNameColumnIndex() const; + virtual std::string getOwnerName(const LLPathfindingObject *pObject) const; + virtual const LLColor4 &getBeaconColor() const; + + virtual LLPathfindingObjectListPtr getEmptyObjectList() const; + +private: + void requestSetLinksets(LLPathfindingObjectListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD); + + void onApplyAllFilters(); + void onClearFiltersClicked(); + void onWalkabilityCoefficientEntered(LLUICtrl *pUICtrl, LLSD &pPreviousValue); + void onApplyChangesClicked(); + + void clearFilters(); + + void updateEditFieldValues(); + LLSD buildLinksetScrollListItemData(const LLPathfindingLinkset *pLinksetPtr, const LLVector3 &pAvatarPosition) const; + LLSD buildLinksetUseScrollListData(const std::string &pLabel, S32 pValue) const; + + bool isShowUnmodifiablePhantomWarning(LLPathfindingLinkset::ELinksetUse pLinksetUse) const; + bool isShowPhantomToggleWarning(LLPathfindingLinkset::ELinksetUse pLinksetUse) const; + bool isShowCannotBeVolumeWarning(LLPathfindingLinkset::ELinksetUse pLinksetUse) const; + + void updateStateOnEditFields(); + void updateStateOnEditLinksetUse(); + + void applyEdit(); + void handleApplyEdit(const LLSD &pNotification, const LLSD &pResponse); + void doApplyEdit(); + + std::string getLinksetUseString(LLPathfindingLinkset::ELinksetUse pLinksetUse) const; + + LLPathfindingLinkset::ELinksetUse getFilterLinksetUse() const; + void setFilterLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse); + + LLPathfindingLinkset::ELinksetUse getEditLinksetUse() const; + void setEditLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse); + + LLPathfindingLinkset::ELinksetUse convertToLinksetUse(LLSD pXuiValue) const; + LLSD convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const; + + LLLineEditor *mFilterByName; + LLLineEditor *mFilterByDescription; + LLComboBox *mFilterByLinksetUse; + LLComboBox *mEditLinksetUse; + LLScrollListItem *mEditLinksetUseUnset; + LLScrollListItem *mEditLinksetUseWalkable; + LLScrollListItem *mEditLinksetUseStaticObstacle; + LLScrollListItem *mEditLinksetUseDynamicObstacle; + LLScrollListItem *mEditLinksetUseMaterialVolume; + LLScrollListItem *mEditLinksetUseExclusionVolume; + LLScrollListItem *mEditLinksetUseDynamicPhantom; + LLTextBox *mLabelWalkabilityCoefficients; + LLTextBox *mLabelEditA; + LLTextBox *mLabelSuggestedUseA; + LLLineEditor *mEditA; + LLTextBox *mLabelEditB; + LLTextBox *mLabelSuggestedUseB; + LLLineEditor *mEditB; + LLTextBox *mLabelEditC; + LLTextBox *mLabelSuggestedUseC; + LLLineEditor *mEditC; + LLTextBox *mLabelEditD; + LLTextBox *mLabelSuggestedUseD; + LLLineEditor *mEditD; + LLButton *mApplyEditsButton; + + LLColor4 mBeaconColor; + + LLSD mPreviousValueA; + LLSD mPreviousValueB; + LLSD mPreviousValueC; + LLSD mPreviousValueD; +}; + +#endif // LL_LLFLOATERPATHFINDINGLINKSETS_H diff --git a/indra/newview/llfloaterpathfindingobjects.cpp b/indra/newview/llfloaterpathfindingobjects.cpp new file mode 100644 index 000000000..bd5cb7bd7 --- /dev/null +++ b/indra/newview/llfloaterpathfindingobjects.cpp @@ -0,0 +1,878 @@ +/** +* @file llfloaterpathfindingobjects.cpp +* @brief Base class for both the pathfinding linksets and characters floater. +* @author Stinson@lindenlab.com +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterpathfindingobjects.h" + +#include +#include +#include + +#include +#include + +#include "llagent.h" +#include "llavatarname.h" +#include "llavatarnamecache.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llenvmanager.h" +#include "llfloater.h" +#include "llfontgl.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llpathfindingmanager.h" +#include "llresmgr.h" +#include "llscrolllistctrl.h" +#include "llselectmgr.h" +#include "llsd.h" +#include "llstring.h" +#include "llstyle.h" +#include "lltextbox.h" +#include "llui.h" +#include "llviewermenu.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "v3dmath.h" +#include "v3math.h" +#include "v4color.h" + +#define DEFAULT_BEACON_WIDTH 6 + +//--------------------------------------------------------------------------- +// LLFloaterPathfindingObjects +//--------------------------------------------------------------------------- + +void LLFloaterPathfindingObjects::onOpen(/*const LLSD &pKey*/) +{ + LLFloater::onOpen(/*pKey*/); + + selectNoneObjects(); + mObjectsScrollList->setCommitOnSelectionChange(TRUE); + + if (!mSelectionUpdateSlot.connected()) + { + mSelectionUpdateSlot = LLSelectMgr::getInstance()->mUpdateSignal.connect(boost::bind(&LLFloaterPathfindingObjects::onInWorldSelectionListChanged, this)); + } + + if (!mRegionBoundaryCrossingSlot.connected()) + { + mRegionBoundaryCrossingSlot = LLEnvManagerNew::getInstance()->setRegionChangeCallback(boost::bind(&LLFloaterPathfindingObjects::onRegionBoundaryCrossed, this)); + } + + if (!mGodLevelChangeSlot.connected()) + { + mGodLevelChangeSlot = gAgent.registerGodLevelChanageListener(boost::bind(&LLFloaterPathfindingObjects::onGodLevelChange, this, _1)); + } + + requestGetObjects(); +} + +void LLFloaterPathfindingObjects::onClose(bool pIsAppQuitting) +{ + if (mGodLevelChangeSlot.connected()) + { + mGodLevelChangeSlot.disconnect(); + } + + if (mRegionBoundaryCrossingSlot.connected()) + { + mRegionBoundaryCrossingSlot.disconnect(); + } + + if (mSelectionUpdateSlot.connected()) + { + mSelectionUpdateSlot.disconnect(); + } + + mObjectsScrollList->setCommitOnSelectionChange(FALSE); + selectNoneObjects(); + + if (mObjectsSelection.notNull()) + { + mObjectsSelection.clear(); + } + + if (pIsAppQuitting) + { + clearAllObjects(); + destroy(); + } + else + { + setVisible(false); + } +} + +void LLFloaterPathfindingObjects::draw() +{ + LLFloater::draw(); + + if (isShowBeacons()) + { + std::vector selectedItems = mObjectsScrollList->getAllSelected(); + if (!selectedItems.empty()) + { + int numSelectedItems = selectedItems.size(); + S32 nameColumnIndex = getNameColumnIndex(); + const LLColor4 &beaconColor = getBeaconColor(); + const LLColor4 &beaconTextColor = getBeaconTextColor(); + S32 beaconWidth = getBeaconWidth(); + + std::vector viewerObjects; + viewerObjects.reserve(numSelectedItems); + + for (std::vector::const_iterator selectedItemIter = selectedItems.begin(); + selectedItemIter != selectedItems.end(); ++selectedItemIter) + { + const LLScrollListItem *selectedItem = *selectedItemIter; + + LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID()); + if (viewerObject != NULL) + { + const std::string &objectName = selectedItem->getColumn(nameColumnIndex)->getValue().asString(); + gObjectList.addDebugBeacon(viewerObject->getPositionAgent(), objectName, beaconColor, beaconTextColor, beaconWidth); + } + } + } + } +} + +LLFloaterPathfindingObjects::LLFloaterPathfindingObjects(/*const LLSD &pSeed*/) + : LLFloater(/*pSeed*/), + mObjectsScrollList(NULL), + mMessagingStatus(NULL), + mRefreshListButton(NULL), + mSelectAllButton(NULL), + mSelectNoneButton(NULL), + mShowBeaconCheckBox(NULL), + mTakeButton(NULL), + mTakeCopyButton(NULL), + mReturnButton(NULL), + mDeleteButton(NULL), + mTeleportButton(NULL), + mDefaultBeaconColor(), + mDefaultBeaconTextColor(), + mErrorTextColor(), + mWarningTextColor(), + mMessagingState(kMessagingUnknown), + mMessagingRequestId(0U), + mMissingNameObjectsScrollListItems(), + mObjectList(), + mObjectsSelection(), + mHasObjectsToBeSelected(false), + mObjectsToBeSelected(), + mSelectionUpdateSlot(), + mRegionBoundaryCrossingSlot() +{ +} + +LLFloaterPathfindingObjects::~LLFloaterPathfindingObjects() +{ + clearAllObjects(); +} + +BOOL LLFloaterPathfindingObjects::postBuild() +{ + mDefaultBeaconColor = LLUI::sColorsGroup->getColor("PathfindingDefaultBeaconColor"); + mDefaultBeaconTextColor = LLUI::sColorsGroup->getColor("PathfindingDefaultBeaconTextColor"); + mErrorTextColor = LLUI::sColorsGroup->getColor("PathfindingErrorColor"); + mWarningTextColor = LLUI::sColorsGroup->getColor("PathfindingWarningColor"); + + mObjectsScrollList = getChild("objects_scroll_list"); + llassert(mObjectsScrollList != NULL); + mObjectsScrollList->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onScrollListSelectionChanged, this)); + mObjectsScrollList->sortByColumnIndex(static_cast(getNameColumnIndex()), TRUE); + + mMessagingStatus = getChild("messaging_status"); + llassert(mMessagingStatus != NULL); + + mRefreshListButton = getChild("refresh_objects_list"); + llassert(mRefreshListButton != NULL); + mRefreshListButton->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onRefreshObjectsClicked, this)); + + mSelectAllButton = getChild("select_all_objects"); + llassert(mSelectAllButton != NULL); + mSelectAllButton->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onSelectAllObjectsClicked, this)); + + mSelectNoneButton = getChild("select_none_objects"); + llassert(mSelectNoneButton != NULL); + mSelectNoneButton->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onSelectNoneObjectsClicked, this)); + + mShowBeaconCheckBox = getChild("show_beacon"); + llassert(mShowBeaconCheckBox != NULL); + + mTakeButton = getChild("take_objects"); + llassert(mTakeButton != NULL); + mTakeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onTakeClicked, this)); + + mTakeCopyButton = getChild("take_copy_objects"); + llassert(mTakeCopyButton != NULL); + mTakeCopyButton->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onTakeCopyClicked, this)); + + mReturnButton = getChild("return_objects"); + llassert(mReturnButton != NULL); + mReturnButton->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onReturnClicked, this)); + + mDeleteButton = getChild("delete_objects"); + llassert(mDeleteButton != NULL); + mDeleteButton->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onDeleteClicked, this)); + + mTeleportButton = getChild("teleport_me_to_object"); + llassert(mTeleportButton != NULL); + mTeleportButton->setCommitCallback(boost::bind(&LLFloaterPathfindingObjects::onTeleportClicked, this)); + + return LLFloater::postBuild(); +} + +void LLFloaterPathfindingObjects::requestGetObjects() +{ + llassert(0); +} + +LLPathfindingManager::request_id_t LLFloaterPathfindingObjects::getNewRequestId() +{ + return ++mMessagingRequestId; +} + +void LLFloaterPathfindingObjects::handleNewObjectList(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::ERequestStatus pRequestStatus, LLPathfindingObjectListPtr pObjectList) +{ + llassert(pRequestId <= mMessagingRequestId); + if (pRequestId == mMessagingRequestId) + { + switch (pRequestStatus) + { + case LLPathfindingManager::kRequestStarted : + setMessagingState(kMessagingGetRequestSent); + break; + case LLPathfindingManager::kRequestCompleted : + mObjectList = pObjectList; + rebuildObjectsScrollList(); + setMessagingState(kMessagingComplete); + break; + case LLPathfindingManager::kRequestNotEnabled : + clearAllObjects(); + setMessagingState(kMessagingNotEnabled); + break; + case LLPathfindingManager::kRequestError : + clearAllObjects(); + setMessagingState(kMessagingGetError); + break; + default : + clearAllObjects(); + setMessagingState(kMessagingGetError); + llassert(0); + break; + } + } +} + +void LLFloaterPathfindingObjects::handleUpdateObjectList(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::ERequestStatus pRequestStatus, LLPathfindingObjectListPtr pObjectList) +{ + // We current assume that handleUpdateObjectList is called only when objects are being SET + llassert(pRequestId <= mMessagingRequestId); + if (pRequestId == mMessagingRequestId) + { + switch (pRequestStatus) + { + case LLPathfindingManager::kRequestStarted : + setMessagingState(kMessagingSetRequestSent); + break; + case LLPathfindingManager::kRequestCompleted : + if (mObjectList == NULL) + { + mObjectList = pObjectList; + } + else + { + mObjectList->update(pObjectList); + } + rebuildObjectsScrollList(); + setMessagingState(kMessagingComplete); + break; + case LLPathfindingManager::kRequestNotEnabled : + clearAllObjects(); + setMessagingState(kMessagingNotEnabled); + break; + case LLPathfindingManager::kRequestError : + clearAllObjects(); + setMessagingState(kMessagingSetError); + break; + default : + clearAllObjects(); + setMessagingState(kMessagingSetError); + llassert(0); + break; + } + } +} + +void LLFloaterPathfindingObjects::rebuildObjectsScrollList() +{ + if (!mHasObjectsToBeSelected) + { + std::vector selectedItems = mObjectsScrollList->getAllSelected(); + int numSelectedItems = selectedItems.size(); + if (numSelectedItems > 0) + { + mObjectsToBeSelected.reserve(selectedItems.size()); + for (std::vector::const_iterator itemIter = selectedItems.begin(); + itemIter != selectedItems.end(); ++itemIter) + { + const LLScrollListItem *listItem = *itemIter; + mObjectsToBeSelected.push_back(listItem->getUUID()); + } + } + } + + S32 origScrollPosition = mObjectsScrollList->getScrollPos(); + mObjectsScrollList->deleteAllItems(); + mMissingNameObjectsScrollListItems.clear(); + + if ((mObjectList != NULL) && !mObjectList->isEmpty()) + { + buildObjectsScrollList(mObjectList); + + mObjectsScrollList->selectMultiple(mObjectsToBeSelected); + if (mHasObjectsToBeSelected) + { + mObjectsScrollList->scrollToShowSelected(); + } + else + { + mObjectsScrollList->setScrollPos(origScrollPosition); + } + } + + mObjectsToBeSelected.clear(); + mHasObjectsToBeSelected = false; + + updateControlsOnScrollListChange(); +} + +void LLFloaterPathfindingObjects::buildObjectsScrollList(const LLPathfindingObjectListPtr pObjectListPtr) +{ + llassert(0); +} + +void LLFloaterPathfindingObjects::addObjectToScrollList(const LLPathfindingObjectPtr pObjectPtr, const LLSD &pScrollListItemData) +{ + LLSD rowParams; + rowParams["id"] = pObjectPtr->getUUID(); + + llassert(pScrollListItemData.isArray()); + S32 idx = 0; + for (LLSD::array_const_iterator cellIter = pScrollListItemData.beginArray(); + cellIter != pScrollListItemData.endArray(); ++cellIter) + { + rowParams["columns"][idx] = *cellIter; + idx++; + } + + LLScrollListItem *scrollListItem = mObjectsScrollList->addElement(rowParams); + + if (pObjectPtr->hasOwner() && !pObjectPtr->hasOwnerName()) + { + mMissingNameObjectsScrollListItems.insert(std::make_pair(pObjectPtr->getUUID().asString(), scrollListItem)); + pObjectPtr->registerOwnerNameListener(boost::bind(&LLFloaterPathfindingObjects::handleObjectNameResponse, this, _1)); + } +} + +void LLFloaterPathfindingObjects::updateControlsOnScrollListChange() +{ + updateMessagingStatus(); + updateStateOnListControls(); + selectScrollListItemsInWorld(); + updateStateOnActionControls(); +} + +void LLFloaterPathfindingObjects::updateControlsOnInWorldSelectionChange() +{ + updateStateOnActionControls(); +} + +S32 LLFloaterPathfindingObjects::getNameColumnIndex() const +{ + return 0; +} + +S32 LLFloaterPathfindingObjects::getOwnerNameColumnIndex() const +{ + return 2; +} + +std::string LLFloaterPathfindingObjects::getOwnerName(const LLPathfindingObject *pObject) const +{ + llassert(0); + std::string returnVal; + return returnVal; +} + +const LLColor4 &LLFloaterPathfindingObjects::getBeaconColor() const +{ + return mDefaultBeaconColor; +} + +const LLColor4 &LLFloaterPathfindingObjects::getBeaconTextColor() const +{ + return mDefaultBeaconTextColor; +} + +S32 LLFloaterPathfindingObjects::getBeaconWidth() const +{ + return DEFAULT_BEACON_WIDTH; +} + +void LLFloaterPathfindingObjects::showFloaterWithSelectionObjects() +{ + mObjectsToBeSelected.clear(); + + LLObjectSelectionHandle selectedObjectsHandle = LLSelectMgr::getInstance()->getSelection(); + if (selectedObjectsHandle.notNull()) + { + LLObjectSelection *selectedObjects = selectedObjectsHandle.get(); + if (!selectedObjects->isEmpty()) + { + for (LLObjectSelection::valid_iterator objectIter = selectedObjects->valid_begin(); + objectIter != selectedObjects->valid_end(); ++objectIter) + { + LLSelectNode *object = *objectIter; + LLViewerObject *viewerObject = object->getObject(); + mObjectsToBeSelected.push_back(viewerObject->getID()); + } + } + } + mHasObjectsToBeSelected = true; + + if (!getVisible()) + { + open(); + setVisibleAndFrontmost(); + } + else + { + rebuildObjectsScrollList(); + if (isMinimized()) + { + setMinimized(FALSE); + } + setVisibleAndFrontmost(); + } + setFocus(TRUE); +} + +BOOL LLFloaterPathfindingObjects::isShowBeacons() const +{ + return mShowBeaconCheckBox->get(); +} + +void LLFloaterPathfindingObjects::clearAllObjects() +{ + selectNoneObjects(); + mObjectsScrollList->deleteAllItems(); + mMissingNameObjectsScrollListItems.clear(); + mObjectList.reset(); +} + +void LLFloaterPathfindingObjects::selectAllObjects() +{ + mObjectsScrollList->selectAll(); +} + +void LLFloaterPathfindingObjects::selectNoneObjects() +{ + mObjectsScrollList->deselectAllItems(); +} + +void LLFloaterPathfindingObjects::teleportToSelectedObject() +{ + std::vector selectedItems = mObjectsScrollList->getAllSelected(); + llassert(selectedItems.size() == 1); + if (selectedItems.size() == 1) + { + std::vector::const_reference selectedItemRef = selectedItems.front(); + const LLScrollListItem *selectedItem = selectedItemRef; + llassert(mObjectList != NULL); + LLVector3d teleportLocation; + LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID()); + if (viewerObject == NULL) + { + // If we cannot find the object in the viewer list, teleport to the last reported position + const LLPathfindingObjectPtr objectPtr = mObjectList->find(selectedItem->getUUID().asString()); + teleportLocation = gAgent.getPosGlobalFromAgent(objectPtr->getLocation()); + } + else + { + // If we can find the object in the viewer list, teleport to the known current position + teleportLocation = viewerObject->getPositionGlobal(); + } + gAgent.teleportViaLocationLookAt(teleportLocation); + } +} + +LLPathfindingObjectListPtr LLFloaterPathfindingObjects::getEmptyObjectList() const +{ + llassert(0); + LLPathfindingObjectListPtr objectListPtr(new LLPathfindingObjectList()); + return objectListPtr; +} + +int LLFloaterPathfindingObjects::getNumSelectedObjects() const +{ + return mObjectsScrollList->getNumSelected(); +} + +LLPathfindingObjectListPtr LLFloaterPathfindingObjects::getSelectedObjects() const +{ + LLPathfindingObjectListPtr selectedObjects = getEmptyObjectList(); + + std::vector selectedItems = mObjectsScrollList->getAllSelected(); + if (!selectedItems.empty()) + { + for (std::vector::const_iterator itemIter = selectedItems.begin(); + itemIter != selectedItems.end(); ++itemIter) + { + LLPathfindingObjectPtr objectPtr = findObject(*itemIter); + if (objectPtr != NULL) + { + selectedObjects->update(objectPtr); + } + } + } + + return selectedObjects; +} + +LLPathfindingObjectPtr LLFloaterPathfindingObjects::getFirstSelectedObject() const +{ + LLPathfindingObjectPtr objectPtr; + + std::vector selectedItems = mObjectsScrollList->getAllSelected(); + if (!selectedItems.empty()) + { + objectPtr = findObject(selectedItems.front()); + } + + return objectPtr; +} + +LLFloaterPathfindingObjects::EMessagingState LLFloaterPathfindingObjects::getMessagingState() const +{ + return mMessagingState; +} + +void LLFloaterPathfindingObjects::setMessagingState(EMessagingState pMessagingState) +{ + mMessagingState = pMessagingState; + updateControlsOnScrollListChange(); +} + +void LLFloaterPathfindingObjects::onRefreshObjectsClicked() +{ + requestGetObjects(); +} + +void LLFloaterPathfindingObjects::onSelectAllObjectsClicked() +{ + selectAllObjects(); +} + +void LLFloaterPathfindingObjects::onSelectNoneObjectsClicked() +{ + selectNoneObjects(); +} + +void LLFloaterPathfindingObjects::onTakeClicked() +{ + handle_take(); + requestGetObjects(); +} + +void LLFloaterPathfindingObjects::onTakeCopyClicked() +{ + handle_take_copy(); +} + +void LLFloaterPathfindingObjects::onReturnClicked() +{ + LLNotification::Params params("PathfindingReturnMultipleItems"); + params.functor(boost::bind(&LLFloaterPathfindingObjects::handleReturnItemsResponse, this, _1, _2)); + + LLSD substitutions; + int numItems = getNumSelectedObjects(); + substitutions["NUM_ITEMS"] = static_cast(numItems); + params.substitutions = substitutions; + + if (numItems == 1) + { + LLNotifications::getInstance()->forceResponse(params, 0); + } + else if (numItems > 1) + { + LLNotifications::getInstance()->add(params); + } +} + +void LLFloaterPathfindingObjects::onDeleteClicked() +{ + LLNotification::Params params("PathfindingDeleteMultipleItems"); + params.functor(boost::bind(&LLFloaterPathfindingObjects::handleDeleteItemsResponse, this, _1, _2)); + + LLSD substitutions; + int numItems = getNumSelectedObjects(); + substitutions["NUM_ITEMS"] = static_cast(numItems); + params.substitutions = substitutions; + + if (numItems == 1) + { + LLNotifications::getInstance()->forceResponse(params, 0); + } + else if (numItems > 1) + { + LLNotifications::getInstance()->add(params); + } +} + +void LLFloaterPathfindingObjects::onTeleportClicked() +{ + teleportToSelectedObject(); +} + +void LLFloaterPathfindingObjects::onScrollListSelectionChanged() +{ + updateControlsOnScrollListChange(); +} + +void LLFloaterPathfindingObjects::onInWorldSelectionListChanged() +{ + updateControlsOnInWorldSelectionChange(); +} + +void LLFloaterPathfindingObjects::onRegionBoundaryCrossed() +{ + requestGetObjects(); +} + +void LLFloaterPathfindingObjects::onGodLevelChange(U8 pGodLevel) +{ + requestGetObjects(); +} + +void LLFloaterPathfindingObjects::handleObjectNameResponse(const LLPathfindingObject *pObject) +{ + llassert(pObject != NULL); + const std::string uuid = pObject->getUUID().asString(); + scroll_list_item_map::iterator scrollListItemIter = mMissingNameObjectsScrollListItems.find(uuid); + if (scrollListItemIter != mMissingNameObjectsScrollListItems.end()) + { + LLScrollListItem *scrollListItem = scrollListItemIter->second; + llassert(scrollListItem != NULL); + + LLScrollListCell *scrollListCell = scrollListItem->getColumn(getOwnerNameColumnIndex()); + LLSD ownerName = getOwnerName(pObject); + + scrollListCell->setValue(ownerName); + + mMissingNameObjectsScrollListItems.erase(scrollListItemIter); + } +} + +void LLFloaterPathfindingObjects::updateMessagingStatus() +{ + std::string statusText(""); + LLColor4 color; + + switch (getMessagingState()) + { + case kMessagingUnknown: + statusText = getString("messaging_initial"); + color = mErrorTextColor; + break; + case kMessagingGetRequestSent : + statusText = getString("messaging_get_inprogress"); + color = mWarningTextColor; + break; + case kMessagingGetError : + statusText = getString("messaging_get_error"); + color = mErrorTextColor; + break; + case kMessagingSetRequestSent : + statusText = getString("messaging_set_inprogress"); + color = mWarningTextColor; + break; + case kMessagingSetError : + statusText = getString("messaging_set_error"); + color = mErrorTextColor; + break; + case kMessagingComplete : + if (mObjectsScrollList->isEmpty()) + { + statusText = getString("messaging_complete_none_found"); + } + else + { + S32 numItems = mObjectsScrollList->getItemCount(); + S32 numSelectedItems = mObjectsScrollList->getNumSelected(); + + LLLocale locale(LLStringUtil::getLocale()); + std::string numItemsString; + LLResMgr::getInstance()->getIntegerString(numItemsString, numItems); + + std::string numSelectedItemsString; + LLResMgr::getInstance()->getIntegerString(numSelectedItemsString, numSelectedItems); + + LLStringUtil::format_map_t string_args; + string_args["[NUM_SELECTED]"] = numSelectedItemsString; + string_args["[NUM_TOTAL]"] = numItemsString; + statusText = getString("messaging_complete_available", string_args); + } + color = LLUI::sColorsGroup->getColor("PathfindingGoodColor"); + break; + case kMessagingNotEnabled : + statusText = getString("messaging_not_enabled"); + color = mErrorTextColor; + break; + default: + statusText = getString("messaging_initial"); + color = mErrorTextColor; + llassert(0); + break; + } + + mMessagingStatus->setText((LLStringExplicit)statusText); + mMessagingStatus->setColor(color); +} + +void LLFloaterPathfindingObjects::updateStateOnListControls() +{ + switch (getMessagingState()) + { + case kMessagingUnknown: + case kMessagingGetRequestSent : + case kMessagingSetRequestSent : + mRefreshListButton->setEnabled(FALSE); + mSelectAllButton->setEnabled(FALSE); + mSelectNoneButton->setEnabled(FALSE); + break; + case kMessagingGetError : + case kMessagingSetError : + case kMessagingNotEnabled : + mRefreshListButton->setEnabled(TRUE); + mSelectAllButton->setEnabled(FALSE); + mSelectNoneButton->setEnabled(FALSE); + break; + case kMessagingComplete : + { + int numItems = mObjectsScrollList->getItemCount(); + int numSelectedItems = mObjectsScrollList->getNumSelected(); + mRefreshListButton->setEnabled(TRUE); + mSelectAllButton->setEnabled(numSelectedItems < numItems); + mSelectNoneButton->setEnabled(numSelectedItems > 0); + } + break; + default: + llassert(0); + break; + } +} + +void LLFloaterPathfindingObjects::updateStateOnActionControls() +{ + int numSelectedItems = mObjectsScrollList->getNumSelected(); + bool isEditEnabled = (numSelectedItems > 0); + + mShowBeaconCheckBox->setEnabled(isEditEnabled); + mTakeButton->setEnabled(isEditEnabled && visible_take_object()); + mTakeCopyButton->setEnabled(isEditEnabled && enable_object_take_copy()); + mReturnButton->setEnabled(isEditEnabled && enable_object_return()); + mDeleteButton->setEnabled(isEditEnabled && enable_object_delete()); + mTeleportButton->setEnabled(numSelectedItems == 1); +} + +void LLFloaterPathfindingObjects::selectScrollListItemsInWorld() +{ + mObjectsSelection.clear(); + LLSelectMgr::getInstance()->deselectAll(); + + std::vector selectedItems = mObjectsScrollList->getAllSelected(); + if (!selectedItems.empty()) + { + int numSelectedItems = selectedItems.size(); + + std::vectorviewerObjects; + viewerObjects.reserve(numSelectedItems); + + for (std::vector::const_iterator selectedItemIter = selectedItems.begin(); + selectedItemIter != selectedItems.end(); ++selectedItemIter) + { + const LLScrollListItem *selectedItem = *selectedItemIter; + + LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID()); + if (viewerObject != NULL) + { + viewerObjects.push_back(viewerObject); + } + } + + if (!viewerObjects.empty()) + { + mObjectsSelection = LLSelectMgr::getInstance()->selectObjectAndFamily(viewerObjects); + } + } +} + +void LLFloaterPathfindingObjects::handleReturnItemsResponse(const LLSD &pNotification, const LLSD &pResponse) +{ + if (LLNotificationsUtil::getSelectedOption(pNotification, pResponse) == 0) + { + handle_object_return(); + requestGetObjects(); + } +} + +void LLFloaterPathfindingObjects::handleDeleteItemsResponse(const LLSD &pNotification, const LLSD &pResponse) +{ + if (LLNotificationsUtil::getSelectedOption(pNotification, pResponse) == 0) + { + handle_object_delete(); + requestGetObjects(); + } +} + +LLPathfindingObjectPtr LLFloaterPathfindingObjects::findObject(const LLScrollListItem *pListItem) const +{ + LLPathfindingObjectPtr objectPtr; + + LLUUID uuid = pListItem->getUUID(); + const std::string &uuidString = uuid.asString(); + llassert(mObjectList != NULL); + objectPtr = mObjectList->find(uuidString); + + return objectPtr; +} diff --git a/indra/newview/llfloaterpathfindingobjects.h b/indra/newview/llfloaterpathfindingobjects.h new file mode 100644 index 000000000..de8c53044 --- /dev/null +++ b/indra/newview/llfloaterpathfindingobjects.h @@ -0,0 +1,179 @@ +/** +* @file llfloaterpathfindingobjects.h +* @brief Base class for both the pathfinding linksets and characters floater. +* @author Stinson@lindenlab.com +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLFLOATERPATHFINDINGOBJECTS_H +#define LL_LLFLOATERPATHFINDINGOBJECTS_H + +#include +#include + +#include + +#include "llagent.h" +#include "llfloater.h" +#include "llpathfindingmanager.h" +#include "llpathfindingobject.h" +#include "llpathfindingobjectlist.h" +#include "llselectmgr.h" +#include "lluuid.h" +#include "v4color.h" + +class LLAvatarName; +class LLButton; +class LLCheckBoxCtrl; +class LLScrollListCtrl; +class LLScrollListItem; +class LLSD; +class LLTextBox; + +class LLFloaterPathfindingObjects : public LLFloater +{ +public: + virtual void onOpen(/*const LLSD &pKey*/); + virtual void onClose(bool pIsAppQuitting); + virtual void draw(); + +protected: +// friend class LLFloaterReg; + + typedef enum + { + kMessagingUnknown, + kMessagingGetRequestSent, + kMessagingGetError, + kMessagingSetRequestSent, + kMessagingSetError, + kMessagingComplete, + kMessagingNotEnabled + } EMessagingState; + + LLFloaterPathfindingObjects(/*const LLSD &pSeed*/); + virtual ~LLFloaterPathfindingObjects(); + + virtual BOOL postBuild(); + + virtual void requestGetObjects(); + LLPathfindingManager::request_id_t getNewRequestId(); + void handleNewObjectList(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::ERequestStatus pRequestStatus, LLPathfindingObjectListPtr pObjectList); + void handleUpdateObjectList(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::ERequestStatus pRequestStatus, LLPathfindingObjectListPtr pObjectList); + + void rebuildObjectsScrollList(); + virtual void buildObjectsScrollList(const LLPathfindingObjectListPtr pObjectListPtr); + void addObjectToScrollList(const LLPathfindingObjectPtr pObjectPr, const LLSD &pScrollListItemData); + + virtual void updateControlsOnScrollListChange(); + virtual void updateControlsOnInWorldSelectionChange(); + + virtual S32 getNameColumnIndex() const; + virtual S32 getOwnerNameColumnIndex() const; + virtual std::string getOwnerName(const LLPathfindingObject *pObject) const; + virtual const LLColor4 &getBeaconColor() const; + virtual const LLColor4 &getBeaconTextColor() const; + virtual S32 getBeaconWidth() const; + + void showFloaterWithSelectionObjects(); + + BOOL isShowBeacons() const; + void clearAllObjects(); + void selectAllObjects(); + void selectNoneObjects(); + void teleportToSelectedObject(); + + virtual LLPathfindingObjectListPtr getEmptyObjectList() const; + int getNumSelectedObjects() const; + LLPathfindingObjectListPtr getSelectedObjects() const; + LLPathfindingObjectPtr getFirstSelectedObject() const; + + EMessagingState getMessagingState() const; + +private: + LLFloaterPathfindingObjects(const LLFloaterPathfindingObjects &pOther); + + void setMessagingState(EMessagingState pMessagingState); + + void onRefreshObjectsClicked(); + void onSelectAllObjectsClicked(); + void onSelectNoneObjectsClicked(); + void onTakeClicked(); + void onTakeCopyClicked(); + void onReturnClicked(); + void onDeleteClicked(); + void onTeleportClicked(); + + void onScrollListSelectionChanged(); + void onInWorldSelectionListChanged(); + void onRegionBoundaryCrossed(); + void onGodLevelChange(U8 pGodLevel); + + void handleObjectNameResponse(const LLPathfindingObject *pObject); + + void updateMessagingStatus(); + void updateStateOnListControls(); + void updateStateOnActionControls(); + void selectScrollListItemsInWorld(); + + void handleReturnItemsResponse(const LLSD &pNotification, const LLSD &pResponse); + void handleDeleteItemsResponse(const LLSD &pNotification, const LLSD &pResponse); + + LLPathfindingObjectPtr findObject(const LLScrollListItem *pListItem) const; + + LLScrollListCtrl *mObjectsScrollList; + LLTextBox *mMessagingStatus; + LLButton *mRefreshListButton; + LLButton *mSelectAllButton; + LLButton *mSelectNoneButton; + LLCheckBoxCtrl *mShowBeaconCheckBox; + + LLButton *mTakeButton; + LLButton *mTakeCopyButton; + LLButton *mReturnButton; + LLButton *mDeleteButton; + LLButton *mTeleportButton; + + LLColor4 mDefaultBeaconColor; + LLColor4 mDefaultBeaconTextColor; + LLColor4 mErrorTextColor; + LLColor4 mWarningTextColor; + + EMessagingState mMessagingState; + LLPathfindingManager::request_id_t mMessagingRequestId; + + typedef std::map scroll_list_item_map; + scroll_list_item_map mMissingNameObjectsScrollListItems; + + LLPathfindingObjectListPtr mObjectList; + + LLObjectSelectionHandle mObjectsSelection; + + bool mHasObjectsToBeSelected; + uuid_vec_t mObjectsToBeSelected; + + boost::signals2::connection mSelectionUpdateSlot; + boost::signals2::connection mRegionBoundaryCrossingSlot; + LLAgent::god_level_change_slot_t mGodLevelChangeSlot; +}; + +#endif // LL_LLFLOATERPATHFINDINGOBJECTS_H diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 274180174..783c728c0 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -48,7 +48,7 @@ #include "llpathfindingnavmesh.h" #include "llpathfindingnavmeshstatus.h" #include "llpathfindingobject.h" -//#include "llpathinglib.h" +#include "llpathinglib.h" #include "llsingleton.h" #include "llsd.h" #include "lltrans.h" @@ -318,24 +318,23 @@ LLPathfindingManager::~LLPathfindingManager() void LLPathfindingManager::initSystem() { - /*if (LLPathingLib::getInstance() == NULL) + if (LLPathingLib::getInstance() == NULL) { LLPathingLib::initSystem(); - }*/ + } } void LLPathfindingManager::quitSystem() { - /*if (LLPathingLib::getInstance() != NULL) + if (LLPathingLib::getInstance() != NULL) { LLPathingLib::quitSystem(); - }*/ + } } bool LLPathfindingManager::isPathfindingViewEnabled() const { - return false; - //return (LLPathingLib::getInstance() != NULL); + return (LLPathingLib::getInstance() != NULL); } bool LLPathfindingManager::isPathfindingEnabledForCurrentRegion() const diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 47e2d4d5e..631527d24 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -38,7 +38,7 @@ #include "llagent.h" #include "llbutton.h" #include "llcommandhandler.h" -#include "llviewercontrol.h" +#include "llenvmanager.h" #include "llfloaterbuycurrency.h" #include "llfloaterchat.h" #include "llfloaterdirectory.h" // to spawn search @@ -51,7 +51,10 @@ #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" +#include "llmenuoptionpathfindingrebakenavmesh.h" #include "llnotify.h" +#include "llpathfindingmanager.h" +#include "llpathfindingnavmeshstatus.h" #include "llimview.h" #include "lltextbox.h" #include "llui.h" @@ -64,6 +67,7 @@ #include "llresmgr.h" #include "llworld.h" #include "llstatgraph.h" +#include "llviewercontrol.h" #include "llviewermenu.h" // for gMenuBarView #include "llviewerparcelmgr.h" #include "llviewerthrottle.h" @@ -122,6 +126,8 @@ static void onClickFly(void*); static void onClickPush(void*); static void onClickVoice(void*); static void onClickBuild(void*); +static void onClickPFDirty(void*); +static void onClickPFDisabled(void*); static void onClickSeeAV(void*); static void onClickScripts(void*); static void onClickBuyLand(void*); @@ -136,7 +142,10 @@ LLStatusBar::LLStatusBar(const std::string& name, const LLRect& rect) mBalance(0), mHealth(100), mSquareMetersCredit(0), -mSquareMetersCommitted(0) +mSquareMetersCommitted(0), +mRegionCrossingSlot(), +mNavMeshSlot(), +mIsNavMeshDirty(false) { // status bar can possible overlay menus? setMouseOpaque(FALSE); @@ -169,6 +178,8 @@ mSquareMetersCommitted(0) childSetAction("buyland", onClickBuyLand, this ); childSetAction("buycurrency", onClickBuyCurrency, this ); childSetAction("no_build", onClickBuild, this ); + childSetAction("pf_dirty", onClickPFDirty, this); + childSetAction("pf_disabled", onClickPFDisabled, this); childSetAction("status_SeeAV", onClickSeeAV, this ); childSetAction("no_scripts", onClickScripts, this ); childSetAction("restrictpush", onClickPush, this ); @@ -188,7 +199,10 @@ mSquareMetersCommitted(0) // that don't support currency yet -- MC LLButton* buybtn = getChild("buycurrency"); buybtn->setLabelArg("[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); - + + mRegionCrossingSlot = LLEnvManagerNew::getInstance()->setRegionChangeCallback(boost::bind(&LLStatusBar::createNavMeshStatusListenerForCurrentRegion, this)); + createNavMeshStatusListenerForCurrentRegion(); + // Adding Net Stat Graph S32 x = getRect().getWidth() - 2; S32 y = 0; @@ -232,6 +246,9 @@ LLStatusBar::~LLStatusBar() delete mHealthTimer; mHealthTimer = NULL; + mRegionCrossingSlot.disconnect(); + mNavMeshSlot.disconnect(); + // LLView destructor cleans up children } @@ -457,6 +474,22 @@ void LLStatusBar::refresh() x += buttonRect.getWidth(); } + if (region) + { + bool pf_disabled = !region->dynamicPathfindingEnabled(); + getChild("pf_dirty")->setVisible(mIsNavMeshDirty); + getChild("pf_disabled")->setVisible(pf_disabled); + const std::string pf_icon = mIsNavMeshDirty ? "pf_dirty" : pf_disabled ? "pf_disabled" : ""; + if (!pf_icon.empty()) + { + x += 6; + childGetRect(pf_icon, buttonRect); + r.setOriginAndSize(x, y, buttonRect.getWidth(), buttonRect.getHeight()); + childSetRect(pf_icon, r); + x += buttonRect.getWidth(); + } + } + BOOL canBuyLand = parcel && !parcel->isPublic() && LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, false); @@ -767,6 +800,47 @@ static void onClickBuild(void*) LLNotificationsUtil::add("NoBuild"); } +static bool rebakeRegionCallback(const LLSD& n, const LLSD& r) +{ + if(!LLNotificationsUtil::getSelectedOption(n, r)) //0 is Yes + { + LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); + return true; + } + return false; +} + +static void onClickPFDirty(void*) +{ + LLNotificationsUtil::add("PathfindingDirty", LLSD(), LLSD(), rebakeRegionCallback); +} + +static void onClickPFDisabled(void*) +{ + LLNotificationsUtil::add("DynamicPathfindingDisabled"); +} + +void LLStatusBar::createNavMeshStatusListenerForCurrentRegion() +{ + if (mNavMeshSlot.connected()) + { + mNavMeshSlot.disconnect(); + } + + LLViewerRegion *currentRegion = gAgent.getRegion(); + if (currentRegion != NULL) + { + mNavMeshSlot = LLPathfindingManager::getInstance()->registerNavMeshListenerForRegion(currentRegion, boost::bind(&LLStatusBar::onNavMeshStatusChange, this, _2)); + LLPathfindingManager::getInstance()->requestGetNavMeshForRegion(currentRegion, true); + } +} + +void LLStatusBar::onNavMeshStatusChange(const LLPathfindingNavMeshStatus &pNavMeshStatus) +{ + mIsNavMeshDirty = pNavMeshStatus.isValid() && (pNavMeshStatus.getStatus() != LLPathfindingNavMeshStatus::kComplete); + refresh(); +} + static void onClickSeeAV(void*) { LLNotificationsUtil::add("SeeAvatars"); diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 0782e9fd0..144047166 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -34,6 +34,7 @@ #define LL_LLSTATUSBAR_H #include "llpanel.h" +#include "llpathfindingnavmesh.h" // "Constants" loaded from settings.xml at start time extern S32 STATUS_BAR_HEIGHT; @@ -47,6 +48,7 @@ class LLUICtrl; class LLUUID; class LLFrameTimer; class LLStatGraph; +class LLPathfindingNavMeshStatus; class LLStatusBar : public LLPanel @@ -91,6 +93,10 @@ private: static void onClickSearch(void* data); static void onClickStatGraph(void* data); + void onRegionBoundaryCrossed(); + void createNavMeshStatusListenerForCurrentRegion(); + void onNavMeshStatusChange(const LLPathfindingNavMeshStatus &pNavMeshStatus); + private: LLTextBox *mTextBalance; LLTextBox *mTextHealth; @@ -109,6 +115,9 @@ private: S32 mSquareMetersCommitted; LLFrameTimer* mBalanceTimer; LLFrameTimer* mHealthTimer; + boost::signals2::connection mRegionCrossingSlot; + LLPathfindingNavMesh::navmesh_slot_t mNavMeshSlot; + bool mIsNavMeshDirty; static std::vector sDays; static std::vector sMonths; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 7cec043dd..fbf90b842 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -141,6 +141,8 @@ #include "llfloatermute.h" #include "llfloateropenobject.h" #include "llfloateroutbox.h" +#include "llfloaterpathfindingcharacters.h" +#include "llfloaterpathfindinglinksets.h" #include "llfloaterpermissionsmgr.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" @@ -2864,16 +2866,50 @@ class LLObjectMeasure : public view_listener_t } }; +class LLObjectPFLinksetsSelected : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects(); + return true; + } +}; + bool enable_object_select_in_pathfinding_linksets() { return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); } +class LLObjectEnablePFLinksetsSelected : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + return enable_object_select_in_pathfinding_linksets(); + } +}; + +class LLObjectPFCharactersSelected : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects(); + return true; + } +}; + bool enable_object_select_in_pathfinding_characters() { return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); } +class LLObjectEnablePFCharactersSelected : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + return enable_object_select_in_pathfinding_characters(); + } +}; + class LLAvatarAnims : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -4814,7 +4850,14 @@ class LLToolsTakeCopy : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; + handle_take_copy(); + return true; + } +}; + +void handle_take_copy() +{ + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; // [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) ) { @@ -4822,16 +4865,13 @@ class LLToolsTakeCopy : public view_listener_t LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectIsSittingOn f(gAgentAvatarp); if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != NULL) ) - return true; + return; } // [/RLVa:KB] - const LLUUID& category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); - - return true; - } -}; + const LLUUID& category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); +} // You can return an object to its owner if it is on your land. class LLObjectReturn : public view_listener_t @@ -5119,6 +5159,11 @@ class LLToolsBuyOrTake : public view_listener_t } }; +bool visible_take_object() +{ + return !is_selection_buy_not_take() && enable_take(); +} + class LLToolsEnableBuyOrTake : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -5755,31 +5800,42 @@ class LLEditDelete : public view_listener_t } }; +bool enable_object_return() +{ + return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && + (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); +} + class LLObjectEnableDelete : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - bool new_value = -#ifdef HACKED_GODLIKE_VIEWER - TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - (!LLViewerLogin::getInstance()->isInProductionGrid() - && gAgent.isGodlike()) || -# endif - LLSelectMgr::getInstance()->canDoDelete(); -#endif -// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) - if ( (new_value) && (rlv_handler_t::isEnabled()) ) - { - new_value = rlvCanDeleteOrReturn(); - } -// [/RLVa:KB] - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); + gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_delete()); return true; } }; +bool enable_object_delete() +{ + bool new_value = +#ifdef HACKED_GODLIKE_VIEWER + TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + (!LLViewerLogin::getInstance()->isInProductionGrid() + && gAgent.isGodlike()) || +# endif + LLSelectMgr::getInstance()->canDoDelete(); +#endif +// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) + if ( (new_value) && (rlv_handler_t::isEnabled()) ) + { + new_value = rlvCanDeleteOrReturn(); + } +// [/RLVa:KB] + return new_value; +} + class LLEditSearch : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -5789,6 +5845,49 @@ class LLEditSearch : public view_listener_t } }; +class LLObjectsReturnPackage +{ +public: + LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; + ~LLObjectsReturnPackage() + { + mObjectSelection.clear(); + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; + }; + + LLObjectSelectionHandle mObjectSelection; + LLDynamicArray mReturnableObjects; + std::string mError; + LLViewerRegion *mFirstRegion; +}; + +static void return_objects(LLObjectsReturnPackage *objectsReturnPackage, const LLSD& notification, const LLSD& response) +{ + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); + } + + delete objectsReturnPackage; +} + +void handle_object_return() +{ + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); + objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); + + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); + } +} + class LLObjectDelete : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -5799,7 +5898,13 @@ class LLObjectDelete : public view_listener_t return true; } // [/RLVa:KB] + handle_object_delete(); + return true; + } +}; +void handle_object_delete() +{ if (LLSelectMgr::getInstance()) { LLSelectMgr::getInstance()->doDelete(); @@ -5811,9 +5916,8 @@ class LLObjectDelete : public view_listener_t // When deleting an object we may not actually be done // Keep selection so we know what to delete when confirmation is needed about the delete gPieObject->hide(TRUE); - return true; - } -}; + return; +} void handle_force_delete(void*) { @@ -6715,6 +6819,14 @@ class LLShowFloater : public view_listener_t { LLFloaterOutbox::toggleInstance(LLSD()); } + else if (floater_name == "pathfinding_linksets") + { + LLFloaterPathfindingLinksets::toggleInstance(LLSD()); + } + else if (floater_name == "pathfinding_characters") + { + LLFloaterPathfindingCharacters::toggleInstance(LLSD()); + } else // Simple codeless floater { LLFloater* floater = LLUICtrlFactory::getInstance()->getBuiltFloater(floater_name); @@ -6801,6 +6913,14 @@ class LLFloaterVisible : public view_listener_t { new_value = LLFloaterOutbox::instanceVisible(LLSD()); } + else if (floater_name == "pathfinding_linksets") + { + new_value = LLFloaterPathfindingLinksets::instanceVisible(LLSD()); + } + else if (floater_name == "pathfinding_characters") + { + new_value = LLFloaterPathfindingCharacters::instanceVisible(LLSD()); + } gMenuHolder->findControl(control_name)->setValue(new_value); return true; } @@ -8017,8 +8137,17 @@ class LLToolsEnableTakeCopy : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - bool all_valid = false; - if (LLSelectMgr::getInstance()) + gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_take_copy()); + return true; + } +}; + +bool enable_object_take_copy() +{ + bool all_valid = false; + if (LLSelectMgr::getInstance()) + { + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) { all_valid = true; #ifndef HACKED_GODLIKE_VIEWER @@ -8032,10 +8161,9 @@ class LLToolsEnableTakeCopy : public view_listener_t virtual bool apply(LLViewerObject* obj) { // return (!obj->permCopy() || obj->isAttachment()); -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g return (!obj->permCopy() || obj->isAttachment()) || - ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (gAgentAvatarp) && - (gAgentAvatarp->getRoot() == obj) ); + ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->getRoot() == obj) ); // [/RLVa:KB] } } func; @@ -8045,11 +8173,10 @@ class LLToolsEnableTakeCopy : public view_listener_t } #endif // HACKED_GODLIKE_VIEWER } - - gMenuHolder->findControl(userdata["control"].asString())->setValue(all_valid); - return true; } -}; + + return all_valid; +} // class LLToolsEnableAdminDelete : public view_listener_t @@ -9695,6 +9822,11 @@ void initialize_menus() addMenu(new LLEnablePayObject(), "EnablePayObject"); addMenu(new LLEnableEdit(), "EnableEdit"); + addMenu(new LLObjectPFLinksetsSelected(), "Pathfinding.Linksets.Select"); + addMenu(new LLObjectEnablePFLinksetsSelected(), "EnableSelectInPathfindingLinksets"); + addMenu(new LLObjectPFCharactersSelected(), "Pathfinding.Characters.Select"); + addMenu(new LLObjectEnablePFCharactersSelected(), "EnableSelectInPathfindingCharacters"); + addMenu(new LLFloaterVisible(), "FloaterVisible"); addMenu(new LLSomethingSelected(), "SomethingSelected"); addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 5f9c37dd9..9d4d43629 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -99,7 +99,18 @@ void handle_gestures(void*); void handle_sit_down(void*); void handle_object_build(void*); +bool visible_take_object(); +bool enable_object_take_copy(); +bool enable_object_return(); +bool enable_object_delete(); + +// Buy either contents or object itself void handle_buy(); +void handle_take(); +void handle_take_copy(); +void handle_object_return(); +void handle_object_delete(); + // Can anyone take a free copy of the object? // *TODO: Move to separate file bool anyone_copy_selection(LLSelectNode* nodep); @@ -121,11 +132,6 @@ bool handle_go_to(); // Export to XML or Collada void handle_export_selected( void * ); -// Pass in an empty string and this function will build a string that -// describes buyer permissions. -class LLSaleInfo; -class LLPermissions; - class LLViewerMenuHolderGL : public LLMenuHolderGL { public: diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 48afdb169..e51beaf6e 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -4359,12 +4359,12 @@ void LLPipeline::renderDebug() { assertInitialized(); + gGL.color4f(1,1,1,1); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); gGL.setColorMask(true, false); - bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD); if (!hud_only && !mDebugBlips.empty()) @@ -9971,3 +9971,70 @@ void LLPipeline::addDebugBlip(const LLVector3& position, const LLColor4& color) mDebugBlips.push_back(blip); } +void LLPipeline::hideObject( const LLUUID& id ) +{ + LLViewerObject *pVO = gObjectList.findObject( id ); + + if ( pVO ) + { + LLDrawable *pDrawable = pVO->mDrawable; + + if ( pDrawable ) + { + hideDrawable( pDrawable ); + } + } +} + +void LLPipeline::hideDrawable( LLDrawable *pDrawable ) +{ + pDrawable->setState( LLDrawable::FORCE_INVISIBLE ); + markRebuild( pDrawable, LLDrawable::REBUILD_ALL, TRUE ); + //hide the children + LLViewerObject::const_child_list_t& child_list = pDrawable->getVObj()->getChildren(); + for ( LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++ ) + { + LLViewerObject* child = *iter; + LLDrawable* drawable = child->mDrawable; + if ( drawable ) + { + drawable->setState( LLDrawable::FORCE_INVISIBLE ); + markRebuild( drawable, LLDrawable::REBUILD_ALL, TRUE ); + } + } +} + +void LLPipeline::unhideDrawable( LLDrawable *pDrawable ) +{ + pDrawable->clearState( LLDrawable::FORCE_INVISIBLE ); + markRebuild( pDrawable, LLDrawable::REBUILD_ALL, TRUE ); + //restore children + LLViewerObject::const_child_list_t& child_list = pDrawable->getVObj()->getChildren(); + for ( LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + LLDrawable* drawable = child->mDrawable; + if ( drawable ) + { + drawable->clearState( LLDrawable::FORCE_INVISIBLE ); + markRebuild( drawable, LLDrawable::REBUILD_ALL, TRUE ); + } + } +} + +void LLPipeline::restoreHiddenObject( const LLUUID& id ) +{ + LLViewerObject *pVO = gObjectList.findObject( id ); + + if ( pVO ) + { + LLDrawable *pDrawable = pVO->mDrawable; + if ( pDrawable ) + { + unhideDrawable( pDrawable ); + } + } +} + diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index a0e89bbdf..b8ede8af7 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -397,6 +397,9 @@ public: void addDebugBlip(const LLVector3& position, const LLColor4& color); + void hideObject( const LLUUID& id ); + void restoreHiddenObject( const LLUUID& id ); + private: void unloadShaders(); void addToQuickLookup( LLDrawPool* new_poolp ); @@ -404,7 +407,8 @@ private: BOOL updateDrawableGeom(LLDrawable* drawable, BOOL priority); void assertInitializedDoError(); bool assertInitialized() { const bool is_init = isInit(); if (!is_init) assertInitializedDoError(); return is_init; }; - + void hideDrawable( LLDrawable *pDrawable ); + void unhideDrawable( LLDrawable *pDrawable ); public: enum {GPU_CLASS_MAX = 3 }; diff --git a/indra/newview/skins/default/colors_base.xml b/indra/newview/skins/default/colors_base.xml index 51d78e833..77425e8f8 100644 --- a/indra/newview/skins/default/colors_base.xml +++ b/indra/newview/skins/default/colors_base.xml @@ -223,4 +223,14 @@ + + + + + + + + + + diff --git a/indra/newview/skins/default/textures/Pathfinding_Dirty.png b/indra/newview/skins/default/textures/Pathfinding_Dirty.png new file mode 100644 index 0000000000000000000000000000000000000000..4ed8c14427ea005dc77b347d06a9695f2da91290 GIT binary patch literal 963 zcmV;!13dhRP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FZT01FZU(%pXi00007bV*G`2iyn= z3Yj=&l7;_U1}k&TZ~JeQ1lN#`+NS zhx6r}=l|n5&-owVf0x8)a&A`EYKhUPe+?dUyyguzM@LPR7#$N#9}?KupCBzg-RyR` zyG5ODf<~*y=93L~ubn8`aH;aFEPIuAe*zO9)I20%n6YTLtxiyjLEU%Q+t7HUwBm4C zS^gg#ON{CPL=>0auJdnJ@6W&P_}2Nk!)|Xj7>y(JVd0>ZewkHRwgdp~)^6K*xvH`> zSaviiCc4mSlX>}tw_IX0MPhW6#Arl-CQ)KE(Q1?VGK=M`#OTOiw_;jK20I-N{j|L0 z^98jCcw41cO-}fPYG!-#oBFe(M0q!YsY%tSR2K|2dKF1 zn2{gdx0d&2&;Xd|TLu7X05JesU%h-W!>`c-uAwZ%86#9-M1l^+a0XMX4kob@Cr*}g z6(O2FU;w6oWd?w}#f!I=oO-ey02;3Dtg3JStj^!EswpeO1rUZ*vj&2SV)9ruKD?<1 zfbQNuPo>sqrtdo6a5*K80>W zp`}3daPIUw)_4_VV1Lk>BbGD8IdQ1~+}hChSdh&Cfk6nR7&W^EA(Q|DMfOZJ?5(z6 zu1P?~5`aMfdVF*1FAV^l>{S|8Su%Li&`;=bau5oH3KVV+2lFs+t%9eo2cY!$ebO7O l@Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FZT01FZU(%pXi00007bV*G`2iyn= z3Vu>o zCP@770ZEaVKs1m_Ai0xN6;FbQ6&?`7*KS^0);TLXvxy$U{1K)?)&Xd7vBEl`q$m> zZra(`bz&%Lm}7GZ695Dyv7~Cz9ifeTy3V*ffqx`rH5FFdpCz7-UB{XBT^$`A9UJn@ znOPkN1i207%5D1xPZ!Acx1K$nN+zPyvDj6AD6}{loANpw4t3M+lMMjS`OfBjX9os4 z0cdlUBE>LD1O6HS$Z0CJJatQ*45S3nwWwiE;?giYf>xM-J(tZi^tHX(_2m}>{W)ML z&&+cPOMXd|>zXD%(%AI0Vsk*79&ui|JaR%1d7Xm%PC-h{@-T_4RG5pJ}PHJ6up^nw8U3w7$9Fg`u;9JpjJ0hZYEy7CMmpgDq%ioRitfR7kX4}{JmtldDi8y5;?ts zZY>e?fKSlkBfU{R(i`P<6_u-klDI8ocRbeOb$$Md%gz9DwKj!Mm6h;Dx08>C0;XSx z?Kf6BC<#YU5)Q8*pIZJdNCII*>vi0K&@u{?5l75`j^WnT*5i2b=+$2bj znx%YUZ!| zoEDtR=CC)O&>yl}&8;4n?O00vK5m#l%K+dO6t_r{G@Izb=Cubdo%^O$B1-m8jE@4q zl*t!TY<#pMHtlQnxmWd9gk&ASp=9c(qiOZ90Sr@7je`Kn0O$bX1zut0 zPf5`J?PRnPKp4R7Ud37w&t>C9b9|*(*aE;lBkcW~@f(XVU;F{Ec7@1K+ayf@0000< KMNUMnLSTX^SMtID literal 0 HcmV?d00001 diff --git a/indra/newview/skins/default/xui/en-us/floater_pathfinding_characters.xml b/indra/newview/skins/default/xui/en-us/floater_pathfinding_characters.xml new file mode 100644 index 000000000..202f1493f --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/floater_pathfinding_characters.xml @@ -0,0 +1,226 @@ + + + + Querying for pathfinding characters ... + Error detected while querying for pathfinding characters. + + + No pathfinding characters. + [NUM_SELECTED] characters selected out of [NUM_TOTAL]. + This region is not enabled for pathfinding. + [CPU_TIME] µs + [Loading] + [Unknown] + [group] + + + + + + + + + + Characters: + +