summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llavatarlist.cpp1
-rw-r--r--indra/newview/llavatarlist.h5
-rw-r--r--indra/newview/llavatarlistitem.cpp2
-rw-r--r--indra/newview/llavatarlistitem.h9
-rw-r--r--indra/newview/llcofwearables.cpp74
-rw-r--r--indra/newview/llcofwearables.h9
-rw-r--r--indra/newview/lllistcontextmenu.cpp125
-rw-r--r--indra/newview/lllistcontextmenu.h84
-rw-r--r--indra/newview/lloutfitslist.cpp39
-rw-r--r--indra/newview/lloutfitslist.h5
-rw-r--r--indra/newview/llpaneloutfitedit.cpp30
-rw-r--r--indra/newview/llpaneloutfitedit.h4
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp7
-rw-r--r--indra/newview/llpanelpeoplemenus.cpp66
-rw-r--r--indra/newview/llpanelpeoplemenus.h31
-rw-r--r--indra/newview/llpanelteleporthistory.h1
-rw-r--r--indra/newview/llparticipantlist.cpp7
-rw-r--r--indra/newview/llparticipantlist.h4
-rw-r--r--indra/newview/llwearableitemslist.cpp30
-rw-r--r--indra/newview/llwearableitemslist.h20
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_attachment.xml21
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_body_part.xml22
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_clothing.xml42
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_gear.xml16
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_gear.xml50
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_tab.xml41
-rw-r--r--indra/newview/skins/default/xui/en/menu_wearable_list_item.xml58
-rw-r--r--indra/newview/skins/default/xui/en/outfit_accordion_tab.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_cof_wearables.xml3
30 files changed, 694 insertions, 115 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 7094d68292..ddd5d47e78 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -268,6 +268,7 @@ set(viewer_SOURCE_FILES
lllandmarkactions.cpp
lllandmarklist.cpp
lllistbrowser.cpp
+ lllistcontextmenu.cpp
lllistview.cpp
lllocaltextureobject.cpp
lllocationhistory.cpp
@@ -786,6 +787,7 @@ set(viewer_HEADER_FILES
lllandmarklist.h
lllightconstants.h
lllistbrowser.h
+ lllistcontextmenu.h
lllistview.h
lllocaltextureobject.h
lllocationhistory.h
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index 24290ac089..3275d784a3 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -46,6 +46,7 @@
#include "llavatariconctrl.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcachename.h"
+#include "lllistcontextmenu.h"
#include "llrecentpeople.h"
#include "lluuid.h"
#include "llvoiceclient.h"
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index a9320055ca..fffc6e6e73 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -38,6 +38,7 @@
#include "llavatarlistitem.h"
class LLTimer;
+class LLListContextMenu;
/**
* Generic list of avatars.
@@ -77,7 +78,7 @@ public:
uuid_vec_t& getIDs() { return mIDs; }
bool contains(const LLUUID& id);
- void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; }
+ void setContextMenu(LLListContextMenu* menu) { mContextMenu = menu; }
void setSessionID(const LLUUID& session_id) { mSessionID = session_id; }
const LLUUID& getSessionID() { return mSessionID; }
@@ -127,7 +128,7 @@ private:
uuid_vec_t mIDs;
LLUUID mSessionID;
- LLAvatarListItem::ContextMenu* mContextMenu;
+ LLListContextMenu* mContextMenu;
commit_signal_t mRefreshCompleteSignal;
mouse_signal_t mItemDoubleClickSignal;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 5a8ad73c83..c74075d67f 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -1,6 +1,6 @@
/**
* @file llavatarlistitem.cpp
- * @avatar list item source file
+ * @brief avatar list item source file
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index c6fac7a9f1..ba9c3574d5 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -1,6 +1,6 @@
/**
* @file llavatarlistitem.h
- * @avatar list item header file
+ * @brief avatar list item header file
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
@@ -67,13 +67,6 @@ public:
IS_OFFLINE,
} EItemState;
- class ContextMenu
- {
- public:
- virtual void show(LLView* spawning_view, const uuid_vec_t& selected_uuids, S32 x, S32 y) = 0;
- virtual void hide() = 0;
- };
-
/**
* Creates an instance of LLAvatarListItem.
*
diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp
index 7c4ceb3458..47862ad921 100644
--- a/indra/newview/llcofwearables.cpp
+++ b/indra/newview/llcofwearables.cpp
@@ -35,9 +35,13 @@
#include "llcofwearables.h"
#include "llagentdata.h"
+#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llinventory.h"
#include "llinventoryfunctions.h"
+#include "lllistcontextmenu.h"
+#include "llmenugl.h"
+#include "llviewermenu.h"
#include "llwearableitemslist.h"
static LLRegisterPanelClassWrapper<LLCOFAccordionListAdaptor> t_cof_accodion_list_adaptor("accordion_list_adaptor");
@@ -49,14 +53,61 @@ const LLSD REARRANGE = LLSD().with("rearrange", LLSD());
static const LLWearableItemNameComparator WEARABLE_NAME_COMPARATOR;
+//////////////////////////////////////////////////////////////////////////
+
+class CofAttachmentContextMenu : public LLListContextMenu
+{
+protected:
+
+ /*virtual*/ LLContextMenu* createMenu()
+ {
+ return createFromFile("menu_cof_attachment.xml");
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+class CofClothingContextMenu : public LLListContextMenu
+{
+protected:
+
+ /*virtual*/ LLContextMenu* createMenu()
+ {
+ return createFromFile("menu_cof_clothing.xml");
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+class CofBodyPartContextMenu : public LLListContextMenu
+{
+protected:
+
+ /*virtual*/ LLContextMenu* createMenu()
+ {
+ return createFromFile("menu_cof_body_part.xml");
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
LLCOFWearables::LLCOFWearables() : LLPanel(),
mAttachments(NULL),
mClothing(NULL),
mBodyParts(NULL),
mLastSelectedList(NULL)
{
+ mClothingMenu = new CofClothingContextMenu();
+ mAttachmentMenu = new CofAttachmentContextMenu();
+ mBodyPartMenu = new CofBodyPartContextMenu();
};
+LLCOFWearables::~LLCOFWearables()
+{
+ delete mClothingMenu;
+ delete mAttachmentMenu;
+ delete mBodyPartMenu;
+}
// virtual
BOOL LLCOFWearables::postBuild()
@@ -65,6 +116,9 @@ BOOL LLCOFWearables::postBuild()
mClothing = getChild<LLFlatListView>("list_clothing");
mBodyParts = getChild<LLFlatListView>("list_body_parts");
+ mClothing->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mClothingMenu));
+ mAttachments->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mAttachmentMenu));
+ mBodyParts->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mBodyPartMenu));
//selection across different list/tabs is not supported
mAttachments->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mAttachments));
@@ -304,6 +358,14 @@ LLUUID LLCOFWearables::getSelectedUUID()
return mLastSelectedList->getSelectedUUID();
}
+bool LLCOFWearables::getSelectedUUIDs(uuid_vec_t& selected_ids)
+{
+ if (!mLastSelectedList) return false;
+
+ mLastSelectedList->getSelectedUUIDs(selected_ids);
+ return selected_ids.size() != 0;
+}
+
void LLCOFWearables::clear()
{
mAttachments->clear();
@@ -311,4 +373,16 @@ void LLCOFWearables::clear()
mBodyParts->clear();
}
+void LLCOFWearables::onListRightClick(LLUICtrl* ctrl, S32 x, S32 y, LLListContextMenu* menu)
+{
+ if(menu)
+ {
+ uuid_vec_t selected_uuids;
+ if(getSelectedUUIDs(selected_uuids))
+ {
+ menu->show(ctrl, selected_uuids, x, y);
+ }
+ }
+}
+
//EOF
diff --git a/indra/newview/llcofwearables.h b/indra/newview/llcofwearables.h
index 583ee96247..590aa709dd 100644
--- a/indra/newview/llcofwearables.h
+++ b/indra/newview/llcofwearables.h
@@ -40,6 +40,7 @@
#include "llappearancemgr.h"
#include "llinventorymodel.h"
+class LLListContextMenu;
class LLPanelClothingListItem;
class LLPanelBodyPartsListItem;
class LLPanelDeletableWearableListItem;
@@ -115,11 +116,12 @@ public:
LLCOFWearables();
- virtual ~LLCOFWearables() {};
+ virtual ~LLCOFWearables();
/*virtual*/ BOOL postBuild();
LLUUID getSelectedUUID();
+ bool getSelectedUUIDs(uuid_vec_t& selected_ids);
void refresh();
void clear();
@@ -138,6 +140,8 @@ protected:
LLPanelBodyPartsListItem* buildBodypartListItem(LLViewerInventoryItem* item);
LLPanelDeletableWearableListItem* buildAttachemntListItem(LLViewerInventoryItem* item);
+ void onListRightClick(LLUICtrl* ctrl, S32 x, S32 y, LLListContextMenu* menu);
+
LLFlatListView* mAttachments;
LLFlatListView* mClothing;
LLFlatListView* mBodyParts;
@@ -146,6 +150,9 @@ protected:
LLCOFCallbacks mCOFCallbacks;
+ LLListContextMenu* mClothingMenu;
+ LLListContextMenu* mAttachmentMenu;
+ LLListContextMenu* mBodyPartMenu;
};
diff --git a/indra/newview/lllistcontextmenu.cpp b/indra/newview/lllistcontextmenu.cpp
new file mode 100644
index 0000000000..50e969f6bc
--- /dev/null
+++ b/indra/newview/lllistcontextmenu.cpp
@@ -0,0 +1,125 @@
+/**
+ * @file lllistcontextmenu.cpp
+ * @brief Base class of misc lists' context menus
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lllistcontextmenu.h"
+
+// libs
+#include "llmenugl.h" // for LLContextMenu
+
+// newview
+#include "llviewermenu.h" // for LLViewerMenuHolderGL
+
+LLListContextMenu::LLListContextMenu()
+: mMenu(NULL)
+{
+}
+
+LLListContextMenu::~LLListContextMenu()
+{
+ // do not forget delete LLContextMenu* mMenu.
+ // It can have registered Enable callbacks which are called from the LLMenuHolderGL::draw()
+ // via selected item (menu_item_call) by calling LLMenuItemCallGL::buildDrawLabel.
+ // we can have a crash via using callbacks of deleted instance of ContextMenu. EXT-4725
+
+ // menu holder deletes its menus on viewer exit, so we have no way to determine if instance
+ // of mMenu has already been deleted except of using LLHandle. EXT-4762.
+ if (!mMenuHandle.isDead())
+ {
+ mMenu->die();
+ mMenu = NULL;
+ }
+}
+
+void LLListContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
+{
+ if (mMenu)
+ {
+ //preventing parent (menu holder) from deleting already "dead" context menus on exit
+ LLView* parent = mMenu->getParent();
+ if (parent)
+ {
+ parent->removeChild(mMenu);
+ }
+ delete mMenu;
+ mMenu = NULL;
+ mUUIDs.clear();
+ }
+
+ if ( uuids.empty() )
+ {
+ return;
+ }
+
+ mUUIDs.resize(uuids.size());
+ std::copy(uuids.begin(), uuids.end(), mUUIDs.begin());
+
+ mMenu = createMenu();
+ if (!mMenu)
+ {
+ llwarns << "Context menu creation failed" << llendl;
+ return;
+ }
+
+ mMenuHandle = mMenu->getHandle();
+ mMenu->show(x, y);
+ LLMenuGL::showPopup(spawning_view, mMenu, x, y);
+}
+
+void LLListContextMenu::hide()
+{
+ if(mMenu)
+ {
+ mMenu->hide();
+ }
+}
+
+// static
+void LLListContextMenu::handleMultiple(functor_t functor, const uuid_vec_t& ids)
+{
+ uuid_vec_t::const_iterator it;
+ for (it = ids.begin(); it != ids.end(); ++it)
+ {
+ functor(*it);
+ }
+}
+
+// static
+LLContextMenu* LLListContextMenu::createFromFile(const std::string& filename)
+{
+ return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
+ filename, LLContextMenu::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+}
+
+// EOF
diff --git a/indra/newview/lllistcontextmenu.h b/indra/newview/lllistcontextmenu.h
new file mode 100644
index 0000000000..09540a833f
--- /dev/null
+++ b/indra/newview/lllistcontextmenu.h
@@ -0,0 +1,84 @@
+/**
+ * @file lllistcontextmenu.h
+ * @brief Base class of misc lists' context menus
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLISTCONTEXTMENU_H
+#define LL_LLLISTCONTEXTMENU_H
+
+#include "llhandle.h"
+#include "lluuid.h"
+#include "llview.h"
+
+class LLView;
+class LLContextMenu;
+
+/**
+ * Context menu for single or multiple list items.
+ *
+ * Derived classes must implement contextMenu().
+ *
+ * Typical usage:
+ * <code>
+ * my_context_menu->show(parent_view, selected_list_items_ids, x, y);
+ * </code>
+ */
+class LLListContextMenu
+{
+public:
+ LLListContextMenu();
+ virtual ~LLListContextMenu();
+
+ /**
+ * Show the menu at specified coordinates.
+ *
+ * @param spawning_view View to spawn at.
+ * @param uuids An array of list items ids.
+ * @param x Horizontal coordinate in the spawn_view's coordinate frame.
+ * @param y Vertical coordinate in the spawn_view's coordinate frame.
+ */
+ virtual void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y);
+
+ virtual void hide();
+
+protected:
+ typedef boost::function<void (const LLUUID& id)> functor_t;
+
+ virtual LLContextMenu* createMenu() = 0;
+
+ static LLContextMenu* createFromFile(const std::string& filename);
+ static void handleMultiple(functor_t functor, const uuid_vec_t& ids);
+
+ uuid_vec_t mUUIDs;
+ LLContextMenu* mMenu;
+ LLHandle<LLView> mMenuHandle;
+};
+
+#endif // LL_LLLISTCONTEXTMENU_H
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 7ebbddca25..36832c9d16 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -41,8 +41,26 @@
#include "llappearancemgr.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
+#include "lllistcontextmenu.h"
+#include "lltransutil.h"
+#include "llviewermenu.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
#include "llwearableitemslist.h"
+//////////////////////////////////////////////////////////////////////////
+
+class OutfitContextMenu : public LLListContextMenu
+{
+protected:
+ /* virtual */ LLContextMenu* createMenu()
+ {
+ return createFromFile("menu_outfit_tab.xml");
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+
static LLRegisterPanelClassWrapper<LLOutfitsList> t_outfits_list("outfits_list");
LLOutfitsList::LLOutfitsList()
@@ -55,10 +73,14 @@ LLOutfitsList::LLOutfitsList()
gInventory.addObserver(mCategoriesObserver);
gInventory.addObserver(this);
+
+ mOutfitMenu = new OutfitContextMenu();
}
LLOutfitsList::~LLOutfitsList()
{
+ delete mOutfitMenu;
+
if (gInventory.containsObserver(mCategoriesObserver))
{
gInventory.removeObserver(mCategoriesObserver);
@@ -140,6 +162,8 @@ void LLOutfitsList::refreshList(const LLUUID& category_id)
static LLXMLNodePtr accordionXmlNode = getAccordionTabXMLNode();
LLAccordionCtrlTab* tab = LLUICtrlFactory::defaultBuilder<LLAccordionCtrlTab>(accordionXmlNode, NULL, NULL);
+ tab->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onAccordionTabRightClick, this,
+ _1, _2, _3, cat_id));
tab->setName(name);
tab->setTitle(name);
@@ -447,4 +471,19 @@ void LLOutfitsList::applyFilter(const std::string& new_filter_substring)
}
}
+void LLOutfitsList::onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id)
+{
+ LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl);
+ if(mOutfitMenu && tab && tab->getHeaderVisible() && cat_id.notNull())
+ {
+ S32 header_bottom = tab->getLocalRect().getHeight() - tab->getHeaderHeight();
+ if(y >= header_bottom)
+ {
+ uuid_vec_t selected_uuids;
+ selected_uuids.push_back(cat_id);
+ mOutfitMenu->show(ctrl, selected_uuids, x, y);
+ }
+ }
+}
+
// EOF
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index 8eaa39e6f1..b6b3d6ae46 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -41,6 +41,7 @@
class LLAccordionCtrl;
class LLAccordionCtrlTab;
class LLWearableItemsList;
+class LLListContextMenu;
/**
* @class LLOutfitsList
@@ -105,6 +106,8 @@ private:
*/
void applyFilter(const std::string& new_filter_substring);
+ void onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
+
LLInventoryCategoriesObserver* mCategoriesObserver;
LLAccordionCtrl* mAccordion;
@@ -118,6 +121,8 @@ private:
typedef std::map<LLUUID, LLAccordionCtrlTab*> outfits_map_t;
typedef outfits_map_t::value_type outfits_map_value_t;
outfits_map_t mOutfitsMap;
+
+ LLListContextMenu* mOutfitMenu;
};
#endif //LL_LLOUTFITSLIST_H
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index ceb720908a..ae4b288588 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -212,6 +212,7 @@ LLPanelOutfitEdit::LLPanelOutfitEdit()
mCOFWearables(NULL),
mInventoryItemsPanel(NULL),
mCOFObserver(NULL),
+ mGearMenu(NULL),
mCOFDragAndDropObserver(NULL),
mInitialized(false)
{
@@ -254,6 +255,8 @@ BOOL LLPanelOutfitEdit::postBuild()
childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL);
childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::showFilteredFolderWearablesPanel, this), NULL);
childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showFilteredWearablesPanel, this), NULL);
+ childSetCommitCallback("gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
+ childSetCommitCallback("wearables_gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
mCOFWearables = getChild<LLCOFWearables>("cof_wearables_list");
mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onOutfitItemSelectionChange, this));
@@ -692,4 +695,31 @@ bool LLPanelOutfitEdit::switchPanels(LLPanel* switch_from_panel, LLPanel* switch
return false;
}
+void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button)
+{
+ if(!mGearMenu)
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+
+ registrar.add("Gear.OnClick", boost::bind(&LLPanelOutfitEdit::onGearMenuItemClick, this, _2));
+
+ mGearMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ "menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+ mGearMenu->buildDrawLabels();
+ mGearMenu->updateParent(LLMenuGL::sMenuContainer);
+ }
+
+ S32 menu_y = mGearMenu->getRect().getHeight() + clicked_button->getRect().getHeight();
+ LLMenuGL::showPopup(clicked_button, mGearMenu, 0, menu_y);
+}
+
+void LLPanelOutfitEdit::onGearMenuItemClick(const LLSD& data)
+{
+ std::string param = data.asString();
+ if("add" == param)
+ {
+ // TODO
+ }
+}
+
// EOF
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 5ebe1e0406..1bf69c5606 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -58,6 +58,7 @@ class LLScrollListCtrl;
class LLToggleableMenu;
class LLFilterEditor;
class LLFilteredWearableListManager;
+class LLMenuGL;
class LLPanelOutfitEdit : public LLPanel
{
@@ -126,6 +127,8 @@ public:
private:
+ void onGearButtonClick(LLUICtrl* clicked_button);
+ void onGearMenuItemClick(const LLSD& data);
LLTextBox* mCurrentOutfitName;
@@ -149,6 +152,7 @@ private:
std::vector<LLLookItemType> mLookItemTypes;
LLCOFWearables* mCOFWearables;
+ LLMenuGL* mGearMenu;
bool mInitialized;
};
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index 0760c57f8e..a7e8f497d9 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -383,11 +383,8 @@ void LLPanelOutfitsInventory::initListCommandsHandlers()
, _7 // EAcceptance* accept
));
- mCommitCallbackRegistrar.add("panel_outfits_inventory_gear_default.Custom.Action",
- boost::bind(&LLPanelOutfitsInventory::onCustomAction, this, _2));
- mEnableCallbackRegistrar.add("panel_outfits_inventory_gear_default.Enable",
- boost::bind(&LLPanelOutfitsInventory::isActionEnabled, this, _2));
- mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("panel_outfits_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_outfit_gear.xml",
+ gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
}
void LLPanelOutfitsInventory::updateListCommands()
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index 862e32cca8..dc1c422ff0 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -42,6 +42,7 @@
#include "llagent.h"
#include "llagentdata.h" // for gAgentID
#include "llavataractions.h"
+#include "llcallingcard.h" // for LLAvatarTracker
#include "llviewermenu.h" // for gMenuHolder
namespace LLPanelPeopleMenus
@@ -49,64 +50,6 @@ namespace LLPanelPeopleMenus
NearbyMenu gNearbyMenu;
-//== ContextMenu ==============================================================
-
-ContextMenu::ContextMenu()
-: mMenu(NULL)
-{
-}
-
-ContextMenu::~ContextMenu()
-{
- // do not forget delete LLContextMenu* mMenu.
- // It can have registered Enable callbacks which are called from the LLMenuHolderGL::draw()
- // via selected item (menu_item_call) by calling LLMenuItemCallGL::buildDrawLabel.
- // we can have a crash via using callbacks of deleted instance of ContextMenu. EXT-4725
-
- // menu holder deletes its menus on viewer exit, so we have no way to determine if instance
- // of mMenu has already been deleted except of using LLHandle. EXT-4762.
- if (!mMenuHandle.isDead())
- {
- mMenu->die();
- mMenu = NULL;
- }
-}
-
-void ContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
-{
- if (mMenu)
- {
- //preventing parent (menu holder) from deleting already "dead" context menus on exit
- LLView* parent = mMenu->getParent();
- if (parent)
- {
- parent->removeChild(mMenu);
- }
- delete mMenu;
- mMenu = NULL;
- mUUIDs.clear();
- }
-
- if ( uuids.empty() )
- return;
-
- mUUIDs.resize(uuids.size());
- std::copy(uuids.begin(), uuids.end(), mUUIDs.begin());
-
- mMenu = createMenu();
- mMenuHandle = mMenu->getHandle();
- mMenu->show(x, y);
- LLMenuGL::showPopup(spawning_view, mMenu, x, y);
-}
-
-void ContextMenu::hide()
-{
- if(mMenu)
- {
- mMenu->hide();
- }
-}
-
//== NearbyMenu ===============================================================
LLContextMenu* NearbyMenu::createMenu()
@@ -135,8 +78,7 @@ LLContextMenu* NearbyMenu::createMenu()
enable_registrar.add("Avatar.CheckItem", boost::bind(&NearbyMenu::checkContextMenuItem, this, _2));
// create the context menu from the XUI
- return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
- "menu_people_nearby.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+ return createFromFile("menu_people_nearby.xml");
}
else
{
@@ -151,9 +93,7 @@ LLContextMenu* NearbyMenu::createMenu()
enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2));
// create the context menu from the XUI
- return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>
- ("menu_people_nearby_multiselect.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
-
+ return createFromFile("menu_people_nearby_multiselect.xml");
}
}
diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h
index 8e12710afc..e1f8790135 100644
--- a/indra/newview/llpanelpeoplemenus.h
+++ b/indra/newview/llpanelpeoplemenus.h
@@ -33,42 +33,15 @@
#ifndef LL_LLPANELPEOPLEMENUS_H
#define LL_LLPANELPEOPLEMENUS_H
-#include "llavatarlistitem.h"
+#include "lllistcontextmenu.h"
namespace LLPanelPeopleMenus
{
/**
- * Base context menu.
- */
-class ContextMenu : public LLAvatarListItem::ContextMenu
-{
-public:
- ContextMenu();
- virtual ~ContextMenu();
-
- /**
- * Show the menu at specified coordinates.
- *
- * @param uuids - an array of avatar or group ids
- */
- /*virtual*/ void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y);
-
- virtual void hide();
-
-protected:
-
- virtual LLContextMenu* createMenu() = 0;
-
- uuid_vec_t mUUIDs;
- LLContextMenu* mMenu;
- LLHandle<LLView> mMenuHandle;
-};
-
-/**
* Menu used in the nearby people list.
*/
-class NearbyMenu : public ContextMenu
+class NearbyMenu : public LLListContextMenu
{
public:
/*virtual*/ LLContextMenu* createMenu();
diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h
index 1f2be63dc2..87e7044222 100644
--- a/indra/newview/llpanelteleporthistory.h
+++ b/indra/newview/llpanelteleporthistory.h
@@ -47,6 +47,7 @@ class LLFlatListView;
class LLTeleportHistoryPanel : public LLPanelPlacesTab
{
public:
+ // *TODO: derive from LLListContextMenu?
class ContextMenu
{
public:
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 1117ae05d7..b975536f8b 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -648,8 +648,7 @@ LLContextMenu* LLParticipantList::LLParticipantListMenu::createMenu()
enable_registrar.add("ParticipantList.CheckItem", boost::bind(&LLParticipantList::LLParticipantListMenu::checkContextMenuItem, this, _2));
// create the context menu from the XUI
- LLContextMenu* main_menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
- "menu_participant_list.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+ LLContextMenu* main_menu = createFromFile("menu_participant_list.xml");
// Don't show sort options for P2P chat
bool is_sort_visible = (mParent.mAvatarList && mParent.mAvatarList->size() > 1);
@@ -666,10 +665,10 @@ LLContextMenu* LLParticipantList::LLParticipantListMenu::createMenu()
void LLParticipantList::LLParticipantListMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
{
- LLPanelPeopleMenus::ContextMenu::show(spawning_view, uuids, x, y);
-
if (uuids.size() == 0) return;
+ LLListContextMenu::show(spawning_view, uuids, x, y);
+
const LLUUID& speaker_id = mUUIDs.front();
BOOL is_muted = isMuted(speaker_id);
diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h
index abaf503868..967c8b78cf 100644
--- a/indra/newview/llparticipantlist.h
+++ b/indra/newview/llparticipantlist.h
@@ -32,8 +32,8 @@
#include "llviewerprecompiledheaders.h"
#include "llevent.h"
-#include "llpanelpeoplemenus.h"
#include "llavatarlist.h" // for LLAvatarItemRecentSpeakerComparator
+#include "lllistcontextmenu.h"
class LLSpeakerMgr;
class LLAvatarList;
@@ -148,7 +148,7 @@ class LLParticipantList
/**
* Menu used in the participant list.
*/
- class LLParticipantListMenu : public LLPanelPeopleMenus::ContextMenu
+ class LLParticipantListMenu : public LLListContextMenu
{
public:
LLParticipantListMenu(LLParticipantList& parent):mParent(parent){};
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index b209dfecce..5836252eac 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -35,8 +35,10 @@
#include "lliconctrl.h"
+#include "llagentwearables.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
+#include "llmenugl.h" // for LLContextMenu
#include "lltransutil.h"
class LLFindOutfitItems : public LLInventoryCollectFunctor
@@ -377,12 +379,17 @@ static const LLWearableItemTypeNameComparator WEARABLE_TYPE_NAME_COMPARATOR;
static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_items_list");
LLWearableItemsList::Params::Params()
+: use_internal_context_menu("use_internal_context_menu", true)
{}
LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p)
: LLInventoryItemsList(p)
{
setComparator(&WEARABLE_TYPE_NAME_COMPARATOR);
+ if (p.use_internal_context_menu)
+ {
+ setRightMouseDownCallback(boost::bind(&LLWearableItemsList::onRightClick, this, _2, _3));
+ }
}
// virtual
@@ -406,4 +413,27 @@ void LLWearableItemsList::updateList(const LLUUID& category_id)
refreshList(item_array);
}
+void LLWearableItemsList::onRightClick(S32 x, S32 y)
+{
+ uuid_vec_t selected_uuids;
+
+ getSelectedUUIDs(selected_uuids);
+ if (selected_uuids.empty())
+ {
+ return;
+ }
+
+ ContextMenu::instance().show(this, selected_uuids, x, y);
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// ContextMenu
+//////////////////////////////////////////////////////////////////////////
+
+// virtual
+LLContextMenu* LLWearableItemsList::ContextMenu::createMenu()
+{
+ return createFromFile("menu_wearable_list_item.xml");
+}
+
// EOF
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
index 2cab5a07a2..d7b09ca934 100644
--- a/indra/newview/llwearableitemslist.h
+++ b/indra/newview/llwearableitemslist.h
@@ -32,11 +32,14 @@
#ifndef LL_LLWEARABLEITEMSLIST_H
#define LL_LLWEARABLEITEMSLIST_H
+// libs
#include "llpanel.h"
+#include "llsingleton.h"
// newview
#include "llinventoryitemslist.h"
#include "llinventorymodel.h"
+#include "lllistcontextmenu.h"
#include "llwearabletype.h"
/**
@@ -274,8 +277,23 @@ private:
class LLWearableItemsList : public LLInventoryItemsList
{
public:
+ /**
+ * Context menu.
+ *
+ * This menu is likely to be used from outside
+ * (e.g. for items selected across multiple wearable lists),
+ * so making it a singleton.
+ */
+ class ContextMenu : public LLListContextMenu, public LLSingleton<ContextMenu>
+ {
+ protected:
+ /* virtual */ LLContextMenu* createMenu();
+ };
+
struct Params : public LLInitParam::Block<Params, LLInventoryItemsList::Params>
{
+ Optional<bool> use_internal_context_menu;
+
Params();
};
@@ -286,6 +304,8 @@ public:
protected:
friend class LLUICtrlFactory;
LLWearableItemsList(const LLWearableItemsList::Params& p);
+
+ void onRightClick(S32 x, S32 y);
};
#endif //LL_LLWEARABLEITEMSLIST_H
diff --git a/indra/newview/skins/default/xui/en/menu_cof_attachment.xml b/indra/newview/skins/default/xui/en/menu_cof_attachment.xml
new file mode 100644
index 0000000000..b422d87938
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_cof_attachment.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="COF Attachment">
+ <menu_item_call
+ label="Detach"
+ layout="topleft"
+ name="detach">
+ <on_click
+ function="Attachment.Detach"
+ parameter="detach"/>
+ </menu_item_call>
+ <context_menu
+ label="Attach to"
+ layout="topleft"
+ name="attach_to" />
+ <context_menu
+ label="Attach to HUD"
+ layout="topleft"
+ name="attach_to_hud" />
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_body_part.xml b/indra/newview/skins/default/xui/en/menu_cof_body_part.xml
new file mode 100644
index 0000000000..01008ef203
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_cof_body_part.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="COF Body">
+ <menu_item_call
+ label="Replace"
+ layout="topleft"
+ name="replace">
+ <on_click
+ function="BodyPart.Replace"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="edit">
+ <on_click
+ function="BodyPart.Edit"/>
+ <on_enable
+ function="BodyPart.OnEnable"
+ parameter="edit" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_clothing.xml b/indra/newview/skins/default/xui/en/menu_cof_clothing.xml
new file mode 100644
index 0000000000..f9cb29f0d7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_cof_clothing.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="COF Clothing">
+ <menu_item_call
+ label="Take Off"
+ layout="topleft"
+ name="take_off">
+ <on_click
+ function="Clothing.TakeOff" />
+ </menu_item_call>
+ <menu_item_call
+ label="Move Up a Layer"
+ layout="topleft"
+ name="move_up">
+ <on_click
+ function="Clothing.MoveUp" />
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="move_up" />
+ </menu_item_call>
+ <menu_item_call
+ label="Move Down a Layer"
+ layout="topleft"
+ name="move_down">
+ <on_click
+ function="Clothing.MoveDown" />
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="move_down" />
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="edit">
+ <on_click
+ function="Clothing.Edit" />
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="edit" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_gear.xml b/indra/newview/skins/default/xui/en/menu_cof_gear.xml
new file mode 100644
index 0000000000..982d4f2015
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_cof_gear.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ layout="topleft"
+ name="Gear COF">
+ <menu_item_call
+ label="Add To Outfit"
+ layout="topleft"
+ name="add">
+ <on_click
+ function="Gear.OnClick"
+ parameter="add"/>
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="add" />
+ </menu_item_call>
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
new file mode 100644
index 0000000000..dfc72b557c
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ layout="topleft"
+ name="Gear Outfit">
+ <menu_item_call
+ label="Wear - Replace Current Outfit"
+ layout="topleft"
+ name="wear">
+ <on_click
+ function="Gear.OnClick"
+ parameter="wear"/>
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="wear" />
+ </menu_item_call>
+ <menu_item_call
+ label="Take Off - Remove Current Outfit"
+ layout="topleft"
+ name="take_off">
+ <on_click
+ function="Gear.OnClick"
+ parameter="take_off"/>
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="take_off" />
+ </menu_item_call>
+ <menu_item_separator />
+ <menu_item_call
+ label="Rename"
+ layout="topleft"
+ name="rename">
+ <on_click
+ function="Gear.OnClick"
+ parameter="rename"/>
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="rename" />
+ </menu_item_call>
+ <menu_item_call
+ label="Delete Outfit"
+ layout="topleft"
+ name="delete_outfit">
+ <on_click
+ function="Gear.OnClick"
+ parameter="delete_outfit"/>
+ <on_enable
+ function="Gear.OnEnable"
+ parameter="delete_outfit" />
+ </menu_item_call>
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
new file mode 100644
index 0000000000..8f3e62157a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Outfit">
+ <menu_item_call
+ label="Wear - Replace Current Outfit"
+ layout="topleft"
+ name="wear_replace">
+ <on_click
+ function="Outfit.WearReplace" />
+ </menu_item_call>
+ <menu_item_call
+ label="Wear - Add to Current Outfit"
+ layout="topleft"
+ name="wear_add">
+ <on_click
+ function="Outfit.WearAdd" />
+ </menu_item_call>
+ <menu_item_call
+ label="Take Off - Remove Current Outfit"
+ layout="topleft"
+ name="take_off">
+ <on_click
+ function="Outfit.TakeOff" />
+ </menu_item_call>
+ <menu_item_separator />
+ <menu_item_call
+ label="Rename"
+ layout="topleft"
+ name="rename">
+ <on_click
+ function="Outfit.Rename" />
+ </menu_item_call>
+ <menu_item_call
+ label="Delete Outfit"
+ layout="topleft"
+ name="delete">
+ <on_click
+ function="Outfit.Delete" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
new file mode 100644
index 0000000000..7ea7eaade5
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ name="Outfit Wearable Context Menu">
+ <menu_item_call
+ label="Wear"
+ layout="topleft"
+ name="wear">
+ <on_click
+ function="Wearable.Wear" />
+ </menu_item_call>
+ <menu_item_call
+ label="Detach"
+ layout="topleft"
+ name="detach">
+ <on_click
+ function="Attachment.Detach" />
+ </menu_item_call>
+<!-- *TODO: implement the submenus
+ <menu
+ label="Attach to"
+ layout="topleft"
+ name="attach_to" />
+ <menu
+ label="Attach to HUD"
+ layout="topleft"
+ name="attach_to_hud" />
+-->
+ <menu_item_call
+ label="Object Profile"
+ layout="topleft"
+ name="object_profile">
+ <on_click
+ function="Attachment.Profile" />
+ </menu_item_call>
+ <menu_item_call
+ label="Take Off"
+ layout="topleft"
+ name="take_off">
+ <on_click
+ function="Clothing.TakeOff"
+ parameter="take_off"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="edit">
+ <on_click
+ function="Wearable.Edit"
+ parameter="edit"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Show Original"
+ layout="topleft"
+ name="show_original">
+ <on_click
+ function="Wearable.ShowOriginal" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml
index 5fcc9b012b..066992b25d 100644
--- a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml
+++ b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml
@@ -15,6 +15,7 @@
allow_select="true"
follows="all"
keep_one_selected="true"
+ multi_select="true"
name="wearable_items_list"
translate="false"
/>
diff --git a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
index 86b9ea6e14..cf84c31078 100644
--- a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
+++ b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
@@ -29,6 +29,7 @@
height="10"
layout="topleft"
left="0"
+ multi_select="true"
name="list_attachments"
top="0"
width="311" />
@@ -63,6 +64,7 @@
height="10"
layout="topleft"
left="0"
+ multi_select="true"
name="list_clothing"
top_pad="0"
width="311" />
@@ -98,6 +100,7 @@
height="10"
layout="topleft"
left="0"
+ multi_select="true"
name="list_body_parts"
top_pad="0"
width="311" />