diff options
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" /> |