From b95b20a1be56ff7baa3ad20e8d0571ec9f07ab12 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 8 Apr 2025 20:28:50 +0300 Subject: #3757 Allow subfolders in "My Outfits" --- indra/newview/lloutfitslist.cpp | 47 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) (limited to 'indra/newview/lloutfitslist.cpp') diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 6e666b8a4b..cfbfe8f8e0 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -819,6 +819,49 @@ void LLOutfitListBase::observerCallback(const LLUUID& category_id) refreshList(category_id); } +class LLIsOutfitListFolder : public LLInventoryCollectFunctor +{ +public: + LLIsOutfitListFolder() + { + mOutfitsId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + } + virtual ~LLIsOutfitListFolder() {} + + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override + { + if (cat) + { + if (cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + return true; + } + if (cat->getPreferredType() == LLFolderType::FT_NONE + && cat->getParentUUID() == mOutfitsId) + { + LLViewerInventoryCategory* inv_cat = dynamic_cast(cat); + if (inv_cat && inv_cat->getDescendentCount() > 3) + { + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + if (items->size() > 3) // eyes, skin, hair and shape are required + { + // For now assume this to be an old style outfit, not a subfolder + // but ideally no such 'outfits' should be left in My Outfits + // Todo: stop counting FT_NONE as outfits, + // convert obvious outfits into FT_OUTFIT + return true; + } + } + } + } + return false; + } +protected: + LLUUID mOutfitsId; +}; + void LLOutfitListBase::refreshList(const LLUUID& category_id) { bool wasNull = mRefreshListState.CategoryUUID.isNull(); @@ -828,13 +871,13 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) LLInventoryModel::item_array_t item_array; // Collect all sub-categories of a given category. - LLIsType is_category(LLAssetType::AT_CATEGORY); + LLIsOutfitListFolder is_outfit; gInventory.collectDescendentsIf( category_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, - is_category); + is_outfit); // Memorize item names for each UUID std::map names; -- cgit v1.3 From 1bb8fb2795920b57a5934ffa394d78a6c5733ce8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 8 Apr 2025 22:39:41 +0300 Subject: #3757 Menu for subfodlers in outfits --- indra/newview/llinventorybridge.cpp | 199 ++++++++++++++++++++++--------- indra/newview/llinventorybridge.h | 2 +- indra/newview/llinventorygallery.cpp | 57 ++++++++- indra/newview/llinventorygallerymenu.cpp | 8 +- indra/newview/llinventorymodel.cpp | 3 +- indra/newview/lloutfitslist.cpp | 3 +- 6 files changed, 202 insertions(+), 70 deletions(-) (limited to 'indra/newview/lloutfitslist.cpp') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 8d31c4dde7..fd9d08a26d 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -105,6 +105,44 @@ static bool check_item(const LLUUID& item_id, // Helper functions + +namespace { + enum EMyOutfitsSubfolderType + { + MY_OUTFITS_NO, + MY_OUTFITS_SUBFOLDER, + MY_OUTFITS_OUTFIT, + }; + + EMyOutfitsSubfolderType myoutfit_object_subfolder_type(LLInventoryModel* model, const LLUUID& obj_id, + const LLUUID& cat_id) + { + if (obj_id == cat_id) return MY_OUTFITS_NO; + + const LLViewerInventoryCategory* test_cat = model->getCategory(obj_id); + while (test_cat) + { + if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + return MY_OUTFITS_OUTFIT; + } + + const LLUUID& parent_id = test_cat->getParentUUID(); + if (parent_id.isNull()) + { + return MY_OUTFITS_NO; + } + if (parent_id == cat_id) + { + return MY_OUTFITS_SUBFOLDER; + } + test_cat = model->getCategory(parent_id); + } + + return MY_OUTFITS_NO; + } +} + bool isAddAction(const std::string& action) { return ("wear" == action || "attach" == action || "activate" == action); @@ -2912,13 +2950,22 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (mUUID == my_outifts_id) { - // Category can contains objects, + // Category can't contains objects, // create a new folder and populate it with links to original objects dropToMyOutfits(inv_cat, cb); } - else if (getCategory() && getCategory()->getParentUUID() == my_outifts_id) + else if (move_is_into_my_outfits) { - dropToMyOutfitsSubfolder(inv_cat, mUUID, cb); + EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); + if (res == MY_OUTFITS_SUBFOLDER) + { + // turn it into outfit + dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_OUTFIT, cb); + } + else + { + dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_NONE, cb); + } } // if target is current outfit folder we use link else if (move_is_into_current_outfit && @@ -4012,6 +4059,7 @@ void LLFolderBridge::perform_pasteFromClipboard() { if (!move_is_into_my_outfits && item && can_move_to_outfit(item, move_is_into_current_outfit)) { + // todo: this is going to create dupplicate folders? dropToOutfit(item, move_is_into_current_outfit, cb); } else if (move_is_into_my_outfits && LLAssetType::AT_CATEGORY == obj->getType()) @@ -4024,9 +4072,18 @@ void LLFolderBridge::perform_pasteFromClipboard() { dropToMyOutfits(cat, cb); } - else if (getCategory() && getCategory()->getParentUUID() == mUUID) + else if (move_is_into_my_outfits) { - dropToMyOutfitsSubfolder(cat, mUUID, cb); + EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); + if (res == MY_OUTFITS_SUBFOLDER) + { + // turn it into outfit + dropToMyOutfitsSubfolder(cat, mUUID, LLFolderType::FT_OUTFIT, cb); + } + else + { + dropToMyOutfitsSubfolder(cat, mUUID, LLFolderType::FT_NONE, cb); + } } } else @@ -4361,63 +4418,85 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items else if(isAgentInventory()) // do not allow creating in library { LLViewerInventoryCategory *cat = getCategory(); - // BAP removed protected check to re-enable standard ops in untyped folders. - // Not sure what the right thing is to do here. - if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) - { - if (!isInboxFolder() // don't allow creation in inbox - && outfits_id != mUUID) - { - bool menu_items_added = false; - // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. - if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) - { - items.push_back(std::string("New Folder")); - menu_items_added = true; - } - if (!isMarketplaceListingsFolder()) - { - items.push_back(std::string("upload_def")); - items.push_back(std::string("create_new")); - items.push_back(std::string("New Script")); - items.push_back(std::string("New Note")); - items.push_back(std::string("New Gesture")); - items.push_back(std::string("New Material")); - items.push_back(std::string("New Clothes")); - items.push_back(std::string("New Body Parts")); - items.push_back(std::string("New Settings")); - if (!LLEnvironment::instance().isInventoryEnabled()) - { - disabled_items.push_back("New Settings"); - } - } - else - { - items.push_back(std::string("New Listing Folder")); - } - if (menu_items_added) - { - items.push_back(std::string("Create Separator")); - } - } - getClipboardEntries(false, items, disabled_items, flags); - } - else + + if (cat) { - // Want some but not all of the items from getClipboardEntries for outfits. - if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT)) + if (cat->getPreferredType() == LLFolderType::FT_OUTFIT) { + // Want some but not all of the items from getClipboardEntries for outfits. + items.push_back(std::string("New Outfit Folder")); items.push_back(std::string("Rename")); items.push_back(std::string("thumbnail")); addDeleteContextMenuOptions(items, disabled_items); // EXT-4030: disallow deletion of currently worn outfit - const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); + const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory())) { disabled_items.push_back(std::string("Delete")); } } + else if (outfits_id == mUUID) + { + getClipboardEntries(false, items, disabled_items, flags); + } + else if (!isCOFFolder()) + { + EMyOutfitsSubfolderType in_my_outfits = myoutfit_object_subfolder_type(model, mUUID, outfits_id); + if (in_my_outfits != MY_OUTFITS_NO) + { + if (in_my_outfits == MY_OUTFITS_SUBFOLDER) + { + // Not inside an outfit, but inside 'my outfits' + items.push_back(std::string("New Outfit")); + } + + items.push_back(std::string("New Outfit Folder")); + items.push_back(std::string("Rename")); + items.push_back(std::string("thumbnail")); + + addDeleteContextMenuOptions(items, disabled_items); + } + else + { + if (!isInboxFolder() // don't allow creation in inbox + && outfits_id != mUUID) + { + bool menu_items_added = false; + // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. + if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) + { + items.push_back(std::string("New Folder")); + menu_items_added = true; + } + if (!isMarketplaceListingsFolder()) + { + items.push_back(std::string("upload_def")); + items.push_back(std::string("create_new")); + items.push_back(std::string("New Script")); + items.push_back(std::string("New Note")); + items.push_back(std::string("New Gesture")); + items.push_back(std::string("New Material")); + items.push_back(std::string("New Clothes")); + items.push_back(std::string("New Body Parts")); + items.push_back(std::string("New Settings")); + if (!LLEnvironment::instance().isInventoryEnabled()) + { + disabled_items.push_back("New Settings"); + } + } + else + { + items.push_back(std::string("New Listing Folder")); + } + if (menu_items_added) + { + items.push_back(std::string("Create Separator")); + } + } + getClipboardEntries(false, items, disabled_items, flags); + } + } } if (model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) == mUUID) @@ -4570,7 +4649,11 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& if (((flags & ITEM_IN_MULTI_SELECTION) == 0) && hasChildren() && (type != LLFolderType::FT_OUTFIT)) { - items.push_back(std::string("Ungroup folder items")); + const LLUUID my_outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + if (!gInventory.isObjectDescendentOf(mUUID, my_outfits)) + { + items.push_back(std::string("Ungroup folder items")); + } } } else @@ -5350,7 +5433,7 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointergetThumbnailUUID()); } -void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLPointer cb) +void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLFolderType::EType preferred_type, LLPointer cb) { LLViewerInventoryCategory* cat = getInventoryModel()->getCategory(dest_id); const LLUUID outfits_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); @@ -5358,7 +5441,7 @@ void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, cons if (cat && cat->getParentUUID() == outfits_id) { getInventoryModel()->createNewCategory(dest_id, - LLFolderType::FT_OUTFIT, + preferred_type, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); @@ -5366,7 +5449,7 @@ void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, cons else { getInventoryModel()->createNewCategory(outfits_id, - LLFolderType::FT_OUTFIT, + preferred_type, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); @@ -5476,10 +5559,6 @@ bool LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, const bool move_is_into_favorites = (mUUID == favorites_id); const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const bool move_is_into_my_outfits_subfolder = move_is_into_my_outfits - && getCategory() - && getCategory()->getParentUUID() == my_outifts_id - && getCategory()->getPreferredType() != LLFolderType::FT_OUTFIT; const bool move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); const bool move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id); @@ -5550,7 +5629,9 @@ bool LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else if (user_confirm && (move_is_into_current_outfit || move_is_into_outfit)) { - accept = !move_is_into_my_outfits_subfolder && can_move_to_outfit(inv_item, move_is_into_current_outfit); + EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); + // don't allow items in my outfits' subfodlers, only in outfits and outfit's subfolders + accept = res != MY_OUTFITS_SUBFOLDER && can_move_to_outfit(inv_item, move_is_into_current_outfit); } else if (user_confirm && (move_is_into_favorites || move_is_into_landmarks)) { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index b7bdef9b21..a101c7368a 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -369,7 +369,7 @@ protected: void dropToFavorites(LLInventoryItem* inv_item, LLPointer cb = NULL); void dropToOutfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit, LLPointer cb = NULL); void dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer cb = NULL); - void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest, LLPointer cb = NULL); + void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest, LLFolderType::EType preferred_type, LLPointer cb = NULL); //-------------------------------------------------------------------- // Messy hacks for handling folder options diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 6188b812d5..15bc578c64 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -60,11 +60,49 @@ static LLPanelInjector t_inventory_gallery("inventory_galler const S32 GALLERY_ITEMS_PER_ROW_MIN = 2; const S32 FAST_LOAD_THUMBNAIL_TRSHOLD = 50; // load folders below this value immediately + +namespace { + enum EMyOutfitsSubfolderType + { + MY_OUTFITS_NO, + MY_OUTFITS_SUBFOLDER, + MY_OUTFITS_OUTFIT, + }; + + EMyOutfitsSubfolderType myoutfit_object_subfolder_type(LLInventoryModel* model, const LLUUID& obj_id, + const LLUUID& cat_id) + { + if (obj_id == cat_id) return MY_OUTFITS_NO; + + const LLViewerInventoryCategory* test_cat = model->getCategory(obj_id); + while (test_cat) + { + if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + return MY_OUTFITS_OUTFIT; + } + + const LLUUID& parent_id = test_cat->getParentUUID(); + if (parent_id.isNull()) + { + return MY_OUTFITS_NO; + } + if (parent_id == cat_id) + { + return MY_OUTFITS_SUBFOLDER; + } + test_cat = model->getCategory(parent_id); + } + + return MY_OUTFITS_NO; + } +} + // Helper dnd functions bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, bool drop, std::string& tooltip_msg, bool is_link); bool dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, bool drop, std::string& tooltip_msg, bool user_confirm); void dropToMyOutfits(LLInventoryCategory* inv_cat); -void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id); +void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLFolderType::EType preferred_type); class LLGalleryPanel: public LLPanel { @@ -3899,9 +3937,18 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, // create a new folder and populate it with links to original objects dropToMyOutfits(inv_cat); } - else if (dest_cat && dest_cat->getParentUUID() == my_outifts_id) + else if (move_is_into_my_outfits) { - dropToMyOutfitsSubfolder(inv_cat, dest_id); + EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, dest_id, my_outifts_id); + if (res == MY_OUTFITS_SUBFOLDER) + { + // turn it into outfit + dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_OUTFIT); + } + else + { + dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_NONE); + } } // if target is current outfit folder we use link else if (move_is_into_current_outfit && @@ -4047,10 +4094,10 @@ void dropToMyOutfits(LLInventoryCategory* inv_cat) gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); } -void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID &dest_id) +void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID &dest_id, LLFolderType::EType preferred_type) { // Note: creation will take time, so passing folder id to callback is slightly unreliable, // but so is collecting and passing descendants' ids inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1); - gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); + gInventory.createNewCategory(dest_id, preferred_type, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); } diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 25b339d51e..3ef5071c97 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -586,7 +586,9 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men bool is_trash = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)); bool is_in_trash = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)); bool is_lost_and_found = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - bool is_outfits= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS)); + const LLUUID my_outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + bool is_outfits= (selected_id == my_outfits); + bool is_in_outfits = is_outfits || gInventory.isObjectDescendentOf(selected_id, my_outfits); bool is_in_favorites = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)); //bool is_favorites= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)); @@ -725,7 +727,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men } else { - if (is_agent_inventory && !is_inbox && !is_cof && !is_in_favorites && !is_outfits) + if (is_agent_inventory && !is_inbox && !is_cof && !is_in_favorites && !is_outfits && !is_in_outfits) { LLViewerInventoryCategory* category = gInventory.getCategory(selected_id); if (!category || !LLFriendCardsManager::instance().isCategoryInFriendFolder(category)) @@ -778,7 +780,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men items.push_back(std::string("Subfolder Separator")); if (!is_system_folder && !isRootFolder()) { - if(has_children && (folder_type != LLFolderType::FT_OUTFIT)) + if(has_children && (folder_type != LLFolderType::FT_OUTFIT) && !is_in_outfits) { items.push_back(std::string("Ungroup folder items")); } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9fffe6378e..6f4d2db12e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1007,7 +1007,8 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, return; } - if (preferred_type != LLFolderType::FT_NONE) + if (preferred_type != LLFolderType::FT_NONE + && preferred_type != LLFolderType::FT_OUTFIT) { // Ultimately this should only be done for non-singleton // types. Requires back-end changes to guarantee that others diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index cfbfe8f8e0..9d8493549d 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -845,7 +845,8 @@ public: LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); - if (items->size() > 3) // eyes, skin, hair and shape are required + if (cats->empty() // protection against outfits inside + && items->size() > 3) // eyes, skin, hair and shape are required { // For now assume this to be an old style outfit, not a subfolder // but ideally no such 'outfits' should be left in My Outfits -- cgit v1.3 From c94e00a10ba6a61bbf5f53fdb2b1c6e345743068 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 13 May 2025 18:21:23 +0300 Subject: #4069 Fix crash at handleToolTip --- indra/newview/lloutfitslist.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'indra/newview/lloutfitslist.cpp') diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 9d8493549d..4ad4cb8d2c 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -1396,7 +1396,12 @@ bool LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) { LLSD params; params["inv_type"] = LLInventoryType::IT_CATEGORY; - params["thumbnail_id"] = gInventory.getCategory(mFolderID)->getThumbnailUUID(); + LLViewerInventoryCategory* cat = gInventory.getCategory(mFolderID); + if (cat) + { + params["thumbnail_id"] = cat->getThumbnailUUID(); + } + // else consider returning params["item_id"] = mFolderID; LLToolTipMgr::instance().show(LLToolTip::Params() -- cgit v1.3 From 888d4ae9dfaf7ba3866c668fbac92502ce252f3b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 13 May 2025 21:39:10 +0300 Subject: #4072 Fix Appearance floater not updating --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/lloutfitgallery.cpp | 11 ++++++ indra/newview/lloutfitslist.cpp | 70 ++++++++++++++++----------------- indra/newview/lloutfitslist.h | 2 + 4 files changed, 49 insertions(+), 36 deletions(-) (limited to 'indra/newview/lloutfitslist.cpp') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 61d2013224..8cfe4f3d97 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7841,7 +7841,7 @@ RenderMinFreeMainMemoryThreshold Comment - Minimum of available physical memory in MB before textures get scaled down + If available free physical memory is below this value textures get agresively scaled down Persist 0 Type diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index b1d5cd9e16..b84b0b3a8c 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -793,6 +793,17 @@ void LLOutfitGallery::updateAddedCategory(LLUUID cat_id) LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); if (!cat) return; + if (!isOutfitFolder(cat)) + { + // Assume a subfolder that contains or will contain outfits, track it + const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + mOutfitsObserver->addCategory(cat_id, [this, outfits]() + { + observerCallback(outfits); + }); + return; + } + std::string name = cat->getName(); LLOutfitGalleryItem* item = buildGalleryItem(name, cat_id); mOutfitMap.insert(LLOutfitGallery::outfit_map_value_t(cat_id, item)); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 4ad4cb8d2c..df53c66ec1 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -142,6 +142,17 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); if (!cat) return; + if (!isOutfitFolder(cat)) + { + // Assume a subfolder that contains or will contain outfits, track it + const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + mCategoriesObserver->addCategory(cat_id, [this, outfits]() + { + observerCallback(outfits); + }); + return; + } + std::string name = cat->getName(); outfit_accordion_tab_params tab_params(get_accordion_tab_params()); @@ -819,49 +830,38 @@ void LLOutfitListBase::observerCallback(const LLUUID& category_id) refreshList(category_id); } -class LLIsOutfitListFolder : public LLInventoryCollectFunctor +bool LLOutfitListBase::isOutfitFolder(LLViewerInventoryCategory* cat) const { -public: - LLIsOutfitListFolder() + if (!cat) { - mOutfitsId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + return false; } - virtual ~LLIsOutfitListFolder() {} - - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override + if (cat->getPreferredType() == LLFolderType::FT_OUTFIT) { - if (cat) + return true; + } + // assumes that folder is somewhere inside MyOutfits + if (cat->getPreferredType() == LLFolderType::FT_NONE) + { + LLViewerInventoryCategory* inv_cat = dynamic_cast(cat); + if (inv_cat && inv_cat->getDescendentCount() > 3) { - if (cat->getPreferredType() == LLFolderType::FT_OUTFIT) + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + if (cats->empty() // protection against outfits inside + && items->size() > 3) // arbitrary, if doesn't have at least base parts, not an outfit { + // For now assume this to be an old style outfit, not a subfolder + // but ideally no such 'outfits' should be left in My Outfits + // Todo: stop counting FT_NONE as outfits, + // convert obvious outfits into FT_OUTFIT return true; } - if (cat->getPreferredType() == LLFolderType::FT_NONE - && cat->getParentUUID() == mOutfitsId) - { - LLViewerInventoryCategory* inv_cat = dynamic_cast(cat); - if (inv_cat && inv_cat->getDescendentCount() > 3) - { - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); - if (cats->empty() // protection against outfits inside - && items->size() > 3) // eyes, skin, hair and shape are required - { - // For now assume this to be an old style outfit, not a subfolder - // but ideally no such 'outfits' should be left in My Outfits - // Todo: stop counting FT_NONE as outfits, - // convert obvious outfits into FT_OUTFIT - return true; - } - } - } } - return false; } -protected: - LLUUID mOutfitsId; -}; + return false; +} void LLOutfitListBase::refreshList(const LLUUID& category_id) { @@ -872,13 +872,13 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) LLInventoryModel::item_array_t item_array; // Collect all sub-categories of a given category. - LLIsOutfitListFolder is_outfit; + LLIsType is_category(LLAssetType::AT_CATEGORY); gInventory.collectDescendentsIf( category_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, - is_outfit); + is_category); // Memorize item names for each UUID std::map names; diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index f581b419d9..fad0e638fb 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -118,6 +118,8 @@ protected: void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response); virtual void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) = 0; + bool isOutfitFolder(LLViewerInventoryCategory* cat) const; + static void onIdle(void* userdata); void onIdleRefreshList(); -- cgit v1.3