From 9f996443604a902e03de87d2d14545b4adffa69c Mon Sep 17 00:00:00 2001 From: Vadim Savchuk <vsavchuk@productengine.com> Date: Thu, 17 Jun 2010 19:03:57 +0300 Subject: [PATCH] EXT-7722 Fixed "Add to COF" and "Remove from COF" outfit context menu items to be enabled when appropriate and work properly. Work on "Take Off - Remove from Current Outfit" and "Wear - Add to Current Outfit" menu options: - The menu items of the outfit context menu and the My Outfits gear menu are now disabled when inappropriate instead of being hidden. - The menu items get enabled/disabled depending on whether you can wear (take off) anything from the selected outfit. (was: depending on whether you're wearing the outfit) - Changed the way the options work: they now only operate on clothes and attachments. "Add to COF" now only adds those body parts that are missing in COF; "Remove from COF" doesn't touch body parts at all. Without this change both "Add" and "Remove" options would be available simultaneously, because any valid outfit contains body parts. I think that would be confusing. And you don't expect you body parts to be replaced when doing "Add to COF'. (that's addition, not replacement) Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/585/ --HG-- branch : product-engine --- indra/newview/llappearancemgr.cpp | 33 ++++++++++++++++++- indra/newview/llappearancemgr.h | 6 ++++ indra/newview/llinventorybridge.cpp | 15 +-------- indra/newview/llinventorybridge.h | 1 - indra/newview/llinventoryfunctions.cpp | 30 ++++++++++++++--- indra/newview/llinventoryfunctions.h | 24 +++++++++----- indra/newview/lloutfitslist.cpp | 16 ++++----- indra/newview/llpaneloutfitsinventory.cpp | 8 ++--- .../skins/default/xui/en/menu_outfit_tab.xml | 6 ++++ 9 files changed, 97 insertions(+), 42 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index be58a562c0c..4e96372da93 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1068,7 +1068,7 @@ void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) { LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; - LLFindWorn collector; + LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); @@ -1224,6 +1224,34 @@ bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) return true; } +// static +bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_worn); + return items.size() > 0; +} + +// static +bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(outfit_cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + not_worn); + return items.size() > 0; +} + void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) { LLInventoryModel::cat_array_t cats; @@ -1338,9 +1366,12 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // - Body parts: always include COF contents as a fallback in case any // required parts are missing. + // Preserve body parts from COF if appending. LLInventoryModel::item_array_t body_items; getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); + if (append) + reverse(body_items.begin(), body_items.end()); // Reduce body items to max of one per type. removeDuplicateItems(body_items); filterWearableItems(body_items, 1); diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index e42f9f7d6f4..8ded32a53d4 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -75,6 +75,12 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> // Determine whether a given outfit can be removed. bool getCanRemoveOutfit(const LLUUID& outfit_cat_id); + // Determine whether we're wearing any of the outfit contents (excluding body parts). + static bool getCanRemoveFromCOF(const LLUUID& outfit_cat_id); + + // Determine whether we can add anything (but body parts) from the outfit contents to COF. + static bool getCanAddToCOF(const LLUUID& outfit_cat_id); + // Copy all items in a category. void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, LLPointer<LLInventoryCallback> cb); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ec367c1746f..1881d0d780e 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2489,7 +2489,7 @@ void LLFolderBridge::folderOptionsMenu() mItems.push_back(std::string("Wear As Ensemble")); } mItems.push_back(std::string("Remove From Outfit")); - if (!areAnyContentsWorn(model)) + if (!LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) { disabled_items.push_back(std::string("Remove From Outfit")); } @@ -2514,19 +2514,6 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv return ((item_array.count() > 0) ? TRUE : FALSE ); } -BOOL LLFolderBridge::areAnyContentsWorn(LLInventoryModel* model) const -{ - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLFindWorn is_worn; - model->collectDescendentsIf(mUUID, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return (item_array.size() > 0); -} - // Flags unused void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 757808eb93c..64d0f8d2545 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -295,7 +295,6 @@ class LLFolderBridge : public LLInvFVBridge static void createNewEyes(void* user_data); BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck); - BOOL areAnyContentsWorn(LLInventoryModel* model) const; void modifyOutfit(BOOL append); void determineFolderType(); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index de24bd92d0c..469d1888dde 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -573,6 +573,31 @@ bool LLFindWearables::operator()(LLInventoryCategory* cat, return FALSE; } +LLFindWearablesEx::LLFindWearablesEx(bool is_worn, bool include_body_parts) +: mIsWorn(is_worn) +, mIncludeBodyParts(include_body_parts) +{} + +bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item); + if (!vitem) return false; + + // Skip non-wearables. + if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT) + { + return false; + } + + // Skip body parts if requested. + if (!mIncludeBodyParts && vitem->getType() == LLAssetType::AT_BODYPART) + { + return false; + } + + return (bool) get_is_item_worn(item->getUUID()) == mIsWorn; +} + bool LLFindWearablesOfType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { if (!item) return false; @@ -593,11 +618,6 @@ void LLFindWearablesOfType::setType(LLWearableType::EType type) mWearableType = type; } -bool LLFindWorn::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -{ - return item && get_is_item_worn(item->getUUID()); -} - bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { if (item) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 93c56e1b8a6..1795b546797 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -337,6 +337,21 @@ class LLFindWearables : public LLInventoryCollectFunctor LLInventoryItem* item); }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindWearablesEx +// +// Collects wearables based on given criteria. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindWearablesEx : public LLInventoryCollectFunctor +{ +public: + LLFindWearablesEx(bool is_worn, bool include_body_parts = true); + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); +private: + bool mIncludeBodyParts; + bool mIsWorn; +}; + //Inventory collect functor collecting wearables of a specific wearable type class LLFindWearablesOfType : public LLInventoryCollectFunctor { @@ -363,15 +378,6 @@ class LLFindActualWearablesOfType : public LLFindWearablesOfType } }; -// Find worn items. -class LLFindWorn : public LLInventoryCollectFunctor -{ -public: - LLFindWorn() {} - virtual ~LLFindWorn() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); -}; - // Collect non-removable folders and items. class LLFindNonRemovableObjects : public LLInventoryCollectFunctor { diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 8c6189353e1..73c850e1fb2 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -102,6 +102,14 @@ class OutfitContextMenu : public LLListContextMenu { return get_is_category_renameable(&gInventory, outfit_cat_id); } + else if ("wear_add" == param) + { + return LLAppearanceMgr::getCanAddToCOF(outfit_cat_id); + } + else if ("take_off" == param) + { + return LLAppearanceMgr::getCanRemoveFromCOF(outfit_cat_id); + } return true; } @@ -119,14 +127,6 @@ class OutfitContextMenu : public LLListContextMenu { return !is_worn; } - else if ("wear_add" == param) - { - return !is_worn; - } - else if ("take_off" == param) - { - return is_worn; - } else if ("delete" == param) { return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id); diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index e2563efb7d5..2405b95e7dd 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -191,6 +191,10 @@ class LLOutfitListGearMenu { return LLAppearanceMgr::instance().getCanRemoveOutfit(selected_outfit_id); } + else if ("take_off" == param) + { + return LLAppearanceMgr::getCanRemoveFromCOF(selected_outfit_id); + } return true; } @@ -209,10 +213,6 @@ class LLOutfitListGearMenu { return !is_worn; } - else if ("take_off" == param) - { - return is_worn; - } return true; } diff --git a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml index e084216a69d..9206969b2f2 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml @@ -18,6 +18,9 @@ name="wear_add"> <on_click function="Outfit.WearAdd" /> + <on_enable + function="Outfit.OnEnable" + parameter="wear_add" /> <on_visible function="Outfit.OnVisible" parameter="wear_add" /> @@ -28,6 +31,9 @@ name="take_off"> <on_click function="Outfit.TakeOff" /> + <on_enable + function="Outfit.OnEnable" + parameter="take_off" /> <on_visible function="Outfit.OnVisible" parameter="take_off" /> -- GitLab