summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2024-10-12 10:37:49 +0300
committerAndrey Lihatskiy <alihatskiy@productengine.com>2024-10-12 10:37:49 +0300
commit33dc262e9a07c01ed33fb3a28edef32439fc908e (patch)
tree6ee5eb01c2a6930905a57a879d5a66df5628bcab
parent6ce9daa13d87fadc03d9ccd819a3e9b3f8748d8d (diff)
parent79b560dcfb33f71da04ecc6c1290e39819ecaf11 (diff)
Merge commit '79b560dcfb' into marchcat/c-develop
# Conflicts: # indra/newview/llfloatermyenvironment.cpp # indra/newview/llhudobject.cpp # indra/newview/llhudobject.h # indra/newview/llviewermenu.cpp
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llfloatermyenvironment.cpp80
-rw-r--r--indra/newview/llfloatermyenvironment.h3
-rw-r--r--indra/newview/llhudeffectresetskeleton.cpp210
-rw-r--r--indra/newview/llhudeffectresetskeleton.h59
-rw-r--r--indra/newview/llhudobject.cpp4
-rw-r--r--indra/newview/llhudobject.h3
-rw-r--r--indra/newview/llviewermenu.cpp42
-rw-r--r--indra/newview/skins/default/xui/en/menu_settings_gear.xml3
9 files changed, 371 insertions, 35 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 3bf01d252d..b0f5116215 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -339,6 +339,7 @@ set(viewer_SOURCE_FILES
llhudeffectpointat.cpp
llhudeffecttrail.cpp
llhudeffectblob.cpp
+ llhudeffectresetskeleton.cpp
llhudicon.cpp
llhudmanager.cpp
llhudnametag.cpp
@@ -1018,6 +1019,7 @@ set(viewer_HEADER_FILES
llhudeffectpointat.h
llhudeffecttrail.h
llhudeffectblob.h
+ llhudeffectresetskeleton.h
llhudicon.h
llhudmanager.h
llhudnametag.h
diff --git a/indra/newview/llfloatermyenvironment.cpp b/indra/newview/llfloatermyenvironment.cpp
index b8aa4c6f72..588f1f7f28 100644
--- a/indra/newview/llfloatermyenvironment.cpp
+++ b/indra/newview/llfloatermyenvironment.cpp
@@ -38,7 +38,9 @@
#include "llcheckboxctrl.h"
#include "llviewerinventory.h"
#include "llenvironment.h"
+#include "llnotificationsutil.h"
#include "llparcel.h"
+#include "lltrans.h"
#include "llviewerparcelmgr.h"
//=========================================================================
@@ -223,6 +225,35 @@ void LLFloaterMyEnvironment::onFilterEdit(const std::string& search_string)
mInventoryList->setFilterSubString(search_string);
}
+void LLFloaterMyEnvironment::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, uuid_vec_t item_ids)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0)
+ {
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ for (const LLUUID& itemid : item_ids)
+ {
+ LLInventoryItem* inv_item = gInventory.getItem(itemid);
+
+ if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_SETTINGS)
+ {
+ LLInventoryModel::update_list_t update;
+ LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1);
+ update.push_back(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
+ update.push_back(new_folder);
+ gInventory.accountForUpdate(update);
+
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item);
+ new_item->setParent(trash_id);
+ new_item->updateParentOnServer(false);
+ gInventory.updateItem(new_item);
+ }
+ }
+ gInventory.notifyObservers();
+ }
+}
+
void LLFloaterMyEnvironment::onDeleteSelected()
{
uuid_vec_t selected;
@@ -231,27 +262,16 @@ void LLFloaterMyEnvironment::onDeleteSelected()
if (selected.empty())
return;
- const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- for (const LLUUID& itemid: selected)
- {
- LLInventoryItem* inv_item = gInventory.getItem(itemid);
-
- if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_SETTINGS)
+ LLSD args;
+ args["QUESTION"] = LLTrans::getString(selected.size() > 1 ? "DeleteItems" : "DeleteItem");
+ LLNotificationsUtil::add(
+ "DeleteItems",
+ args,
+ LLSD(),
+ [this, selected](const LLSD& notification, const LLSD& response)
{
- LLInventoryModel::update_list_t update;
- LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
- update.push_back(new_folder);
- gInventory.accountForUpdate(update);
-
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item);
- new_item->setParent(trash_id);
- new_item->updateParentOnServer(false);
- gInventory.updateItem(new_item);
- }
- }
- gInventory.notifyObservers();
+ onItemsRemovalConfirmation(notification, response, selected);
+ });
}
@@ -318,13 +338,13 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
if (context == PARAMETER_EDIT)
{
- return (selected.size() == 1) && isSettingSelected(selected.front());
+ return (selected.size() == 1) && isSettingId(selected.front());
}
else if (context == PARAMETER_COPY)
{
for (std::vector<LLUUID>::iterator it = selected.begin(); it != selected.end(); it++)
{
- if(!isSettingSelected(*it))
+ if(!isSettingId(*it))
{
return false;
}
@@ -342,7 +362,7 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
LLClipboard::instance().pasteFromClipboard(ids);
for (std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
{
- if (!isSettingSelected(*it))
+ if (!isSettingId(*it))
{
return false;
}
@@ -351,7 +371,7 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
}
else if (context == PARAMETER_COPYUUID)
{
- return (selected.size() == 1) && isSettingSelected(selected.front());
+ return (selected.size() == 1) && isSettingId(selected.front());
}
return false;
@@ -367,16 +387,18 @@ bool LLFloaterMyEnvironment::canApply(const std::string &context)
if (context == PARAMETER_REGION)
{
- return LLEnvironment::instance().canAgentUpdateRegionEnvironment();
+ return isSettingId(selected.front()) && LLEnvironment::instance().canAgentUpdateRegionEnvironment();
}
else if (context == PARAMETER_PARCEL)
{
- return LLEnvironment::instance().canAgentUpdateParcelEnvironment();
+ return isSettingId(selected.front()) && LLEnvironment::instance().canAgentUpdateParcelEnvironment();
}
- else
+ else if (context == PARAMETER_LOCAL)
{
- return (context == PARAMETER_LOCAL);
+ return isSettingId(selected.front());
}
+
+ return false;
}
//-------------------------------------------------------------------------
@@ -438,7 +460,7 @@ LLUUID LLFloaterMyEnvironment::findItemByAssetId(LLUUID asset_id, bool copyable_
return LLUUID::null;
}
-bool LLFloaterMyEnvironment::isSettingSelected(LLUUID item_id)
+bool LLFloaterMyEnvironment::isSettingId(const LLUUID& item_id)
{
LLInventoryItem* itemp = gInventory.getItem(item_id);
diff --git a/indra/newview/llfloatermyenvironment.h b/indra/newview/llfloatermyenvironment.h
index 8e81b8e5e2..c5d521d207 100644
--- a/indra/newview/llfloatermyenvironment.h
+++ b/indra/newview/llfloatermyenvironment.h
@@ -60,6 +60,7 @@ private:
void onFilterCheckChange();
void onFilterEdit(const std::string& search_string);
void onSelectionChange();
+ void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, uuid_vec_t item_ids);
void onDeleteSelected();
void onDoCreate(const LLSD &data);
void onDoApply(const std::string &context);
@@ -69,7 +70,7 @@ private:
void getSelectedIds(uuid_vec_t& ids) const;
void refreshButtonStates();
- bool isSettingSelected(LLUUID item_id);
+ static bool isSettingId(const LLUUID &item_id);
static LLUUID findItemByAssetId(LLUUID asset_id, bool copyable_only, bool ignore_library);
};
diff --git a/indra/newview/llhudeffectresetskeleton.cpp b/indra/newview/llhudeffectresetskeleton.cpp
new file mode 100644
index 0000000000..aa5532f0fc
--- /dev/null
+++ b/indra/newview/llhudeffectresetskeleton.cpp
@@ -0,0 +1,210 @@
+/**
+ * @file llhudeffectresetskeleton.cpp
+ * @brief LLHUDEffectResetSkeleton class implementation
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, 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 "llhudeffectresetskeleton.h"
+
+#include "llagent.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatar.h"
+#include "message.h"
+
+// packet layout
+const S32 TARGET_OBJECT = 0; // This is to allow for targetting owned animesh
+const S32 RESET_ANIMATIONS = 16; //This can also be a flags if needed
+const S32 PKT_SIZE = 17;
+
+//-----------------------------------------------------------------------------
+// LLHUDEffectResetSkeleton()
+//-----------------------------------------------------------------------------
+LLHUDEffectResetSkeleton::LLHUDEffectResetSkeleton(const U8 type) :
+ LLHUDEffect(type)
+{
+}
+
+//-----------------------------------------------------------------------------
+// ~LLHUDEffectResetSkeleton()
+//-----------------------------------------------------------------------------
+LLHUDEffectResetSkeleton::~LLHUDEffectResetSkeleton()
+{
+}
+
+//-----------------------------------------------------------------------------
+// packData()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::packData(LLMessageSystem *mesgsys)
+{
+ // Pack the default data
+ LLHUDEffect::packData(mesgsys);
+
+ // Pack the type-specific data. Uses a fun packed binary format. Whee!
+ U8 packed_data[PKT_SIZE];
+ memset(packed_data, 0, PKT_SIZE);
+
+ // pack both target object and position
+ // position interpreted as offset if target object is non-null
+ if (mTargetObject)
+ {
+ htolememcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16);
+ }
+ else
+ {
+ htolememcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16);
+ }
+
+ U8 resetAnimations = (U8)mResetAnimations;
+ htolememcpy(&(packed_data[RESET_ANIMATIONS]), &resetAnimations, MVT_U8, 1);
+
+ mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE);
+}
+
+//-----------------------------------------------------------------------------
+// unpackData()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
+{
+ LLVector3d new_target;
+ U8 packed_data[PKT_SIZE];
+
+
+ LLHUDEffect::unpackData(mesgsys, blocknum);
+
+ LLUUID source_id;
+ mesgsys->getUUIDFast(_PREHASH_Effect, _PREHASH_AgentID, source_id, blocknum);
+
+ LLViewerObject *objp = gObjectList.findObject(source_id);
+ if (objp && objp->isAvatar())
+ {
+ setSourceObject(objp);
+ }
+ else
+ {
+ //LL_WARNS() << "Could not find source avatar for ResetSkeleton effect" << LL_ENDL;
+ return;
+ }
+
+ S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData);
+ if (size != PKT_SIZE)
+ {
+ LL_WARNS() << "ResetSkeleton effect with bad size " << size << LL_ENDL;
+ return;
+ }
+
+ mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum);
+
+ LLUUID target_id;
+ htolememcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16);
+
+ // The purpose for having a target ID is if we want to reset animesh, or
+ // other things in the future.
+ // I implemented this, but due to issues regarding various permission
+ // checks, I scrapped it for now. --Chaser Zaks
+ // See https://github.com/secondlife/viewer/pull/1212 for additional info
+
+ if (target_id.isNull())
+ {
+ target_id = source_id;
+ }
+
+ objp = gObjectList.findObject(target_id);
+
+ if (objp)
+ {
+ setTargetObject(objp);
+ }
+
+ U8 resetAnimations = 0;
+ htolememcpy(&resetAnimations, &(packed_data[RESET_ANIMATIONS]), MVT_U8, 1);
+
+ // Pre-emptively assume this is going to be flags in the future.
+ // It isn't needed now, but this will assure that only bit 1 is set
+ mResetAnimations = resetAnimations & 1;
+
+ update();
+}
+
+//-----------------------------------------------------------------------------
+// setTargetObjectAndOffset()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::setTargetObject(LLViewerObject *objp)
+{
+ mTargetObject = objp;
+}
+
+
+//-----------------------------------------------------------------------------
+// markDead()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::markDead()
+{
+ LLHUDEffect::markDead();
+}
+
+void LLHUDEffectResetSkeleton::setSourceObject(LLViewerObject* objectp)
+{
+ // restrict source objects to avatars
+ if (objectp && objectp->isAvatar())
+ {
+ LLHUDEffect::setSourceObject(objectp);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// update()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::update()
+{
+ // If the target object is dead, set the target object to NULL
+ if (mTargetObject.isNull() || mTargetObject->isDead())
+ {
+ markDead();
+ return;
+ }
+
+ if (mSourceObject.isNull() || mSourceObject->isDead())
+ {
+ markDead();
+ return;
+ }
+
+ if (mTargetObject->isAvatar())
+ {
+ // Only the owner of a avatar can reset their skeleton like this
+ if (mSourceObject->getID() == mTargetObject->getID())
+ {
+ LLVOAvatar* avatar = mTargetObject->asAvatar();
+ avatar->resetSkeleton(mResetAnimations);
+ }
+ }
+ else
+ {
+ LL_WARNS() << mSourceObject->getID() << " attempted to reset skeleton on "
+ << mTargetObject->getID() << ", but it is not a avatar!" << LL_ENDL;
+ }
+
+ markDead();
+}
diff --git a/indra/newview/llhudeffectresetskeleton.h b/indra/newview/llhudeffectresetskeleton.h
new file mode 100644
index 0000000000..39a6137054
--- /dev/null
+++ b/indra/newview/llhudeffectresetskeleton.h
@@ -0,0 +1,59 @@
+/**
+ * @file llhudeffectresetskeleton.h
+ * @brief LLHUDEffectResetSkeleton class definition
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, 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_LLHUDEFFECTRESETSKELETON_H
+#define LL_LLHUDEFFECTRESETSKELETON_H
+
+#include "llhudeffect.h"
+
+class LLViewerObject;
+class LLVOAvatar;
+
+
+class LLHUDEffectResetSkeleton final : public LLHUDEffect
+{
+public:
+ friend class LLHUDObject;
+
+ /*virtual*/ void markDead();
+ /*virtual*/ void setSourceObject(LLViewerObject* objectp);
+
+ void setTargetObject(LLViewerObject *objp);
+ void setResetAnimations(bool enable){ mResetAnimations = enable; };
+
+protected:
+ LLHUDEffectResetSkeleton(const U8 type);
+ ~LLHUDEffectResetSkeleton();
+
+ /*virtual*/ void packData(LLMessageSystem *mesgsys);
+ /*virtual*/ void unpackData(LLMessageSystem *mesgsys, S32 blocknum);
+
+ void update();
+private:
+ bool mResetAnimations;
+};
+
+#endif // LL_LLHUDEFFECTRESETSKELETON_H
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index e6fbfbfb38..04e9e2dff2 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -36,6 +36,7 @@
#include "llhudeffecttrail.h"
#include "llhudeffectlookat.h"
#include "llhudeffectpointat.h"
+#include "llhudeffectresetskeleton.h"
#include "llhudnametag.h"
#include "llvoicevisualizer.h"
@@ -241,6 +242,9 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type)
case LL_HUD_EFFECT_BLOB:
hud_objectp = new LLHUDEffectBlob(type);
break;
+ case LL_HUD_EFFECT_RESET_SKELETON:
+ hud_objectp = new LLHUDEffectResetSkeleton(type);
+ break;
default:
LL_WARNS() << "Unknown type of hud effect:" << (U32) type << LL_ENDL;
}
diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h
index 8c628e3f92..f683f21e96 100644
--- a/indra/newview/llhudobject.h
+++ b/indra/newview/llhudobject.h
@@ -96,7 +96,8 @@ public:
LL_HUD_EFFECT_POINTAT,
LL_HUD_EFFECT_VOICE_VISUALIZER, // Ventrella
LL_HUD_NAME_TAG,
- LL_HUD_EFFECT_BLOB
+ LL_HUD_EFFECT_BLOB,
+ LL_HUD_EFFECT_RESET_SKELETON
};
protected:
static void sortObjects();
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 120a3094cd..0e3039708b 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -88,6 +88,7 @@
#include "lltoolface.h"
#include "llhints.h"
#include "llhudeffecttrail.h"
+#include "llhudeffectresetskeleton.h"
#include "llhudmanager.h"
#include "llimview.h"
#include "llinventorybridge.h"
@@ -6620,7 +6621,17 @@ class LLAvatarResetSkeleton : public view_listener_t
{
if (LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()))
{
- avatar->resetSkeleton(false);
+ if(avatar->getID() == gAgentID)
+ {
+ LLHUDEffectResetSkeleton* effectp = (LLHUDEffectResetSkeleton*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_RESET_SKELETON, true);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject((LLViewerObject*)avatar);
+ effectp->setResetAnimations(false);
+ }
+ else
+ {
+ avatar->resetSkeleton(false);
+ }
}
return true;
}
@@ -6644,7 +6655,17 @@ class LLAvatarResetSkeletonAndAnimations : public view_listener_t
{
if (LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()))
{
- avatar->resetSkeleton(true);
+ if(avatar->getID() == gAgentID)
+ {
+ LLHUDEffectResetSkeleton* effectp = (LLHUDEffectResetSkeleton*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_RESET_SKELETON, true);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject((LLViewerObject*)avatar);
+ effectp->setResetAnimations(true);
+ }
+ else
+ {
+ avatar->resetSkeleton(true);
+ }
}
return true;
}
@@ -6672,11 +6693,24 @@ class LLAvatarResetSelfSkeletonAndAnimations : public view_listener_t
{
if (LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()))
{
- avatar->resetSkeleton(true);
+ if(avatar->getID() == gAgentID)
+ {
+ LLHUDEffectResetSkeleton* effectp = (LLHUDEffectResetSkeleton*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_RESET_SKELETON, true);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject((LLViewerObject*)avatar);
+ effectp->setResetAnimations(true);
+ }
+ else
+ {
+ avatar->resetSkeleton(true);
+ }
}
else
{
- gAgentAvatarp->resetSkeleton(true);
+ LLHUDEffectResetSkeleton* effectp = (LLHUDEffectResetSkeleton*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_RESET_SKELETON, true);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject(gAgentAvatarp);
+ effectp->setResetAnimations(true);
}
return true;
}
diff --git a/indra/newview/skins/default/xui/en/menu_settings_gear.xml b/indra/newview/skins/default/xui/en/menu_settings_gear.xml
index 57f4aa8655..96cbac4478 100644
--- a/indra/newview/skins/default/xui/en/menu_settings_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_settings_gear.xml
@@ -24,6 +24,9 @@
<menu_item_call.on_click
function="MyEnvironments.DoApply"
parameter="local" />
+ <menu_item_call.on_enable
+ function="MyEnvironments.CanApply"
+ parameter="local"/>
</menu_item_call>
<menu_item_call
name="Settings Apply Parcel"