From a220acb45496dfbfb154fa9e16943102eda922fc Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 22 Apr 2024 23:45:44 +0300 Subject: viewer#1300 Inventory favorites basic framework --- indra/llinventory/llinventory.cpp | 77 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 6334a35fd0..cef469e11e 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -46,6 +46,7 @@ static const std::string INV_ITEM_ID_LABEL("item_id"); static const std::string INV_FOLDER_ID_LABEL("cat_id"); static const std::string INV_PARENT_ID_LABEL("parent_id"); static const std::string INV_THUMBNAIL_LABEL("thumbnail"); +static const std::string INV_FAVORITE_LABEL("favorite"); static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id"); static const std::string INV_ASSET_TYPE_LABEL("type"); static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type"); @@ -82,14 +83,16 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid, mParentUUID(parent_uuid), mType(type), mName(name), - mCreationDate(0) + mCreationDate(0), + mFavorite(false) { correctInventoryName(mName); } LLInventoryObject::LLInventoryObject() : mType(LLAssetType::AT_NONE), - mCreationDate(0) + mCreationDate(0), + mFavorite(false) { } @@ -104,6 +107,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other) mType = other->mType; mName = other->mName; mThumbnailUUID = other->mThumbnailUUID; + mFavorite = other->mFavorite; } const LLUUID& LLInventoryObject::getUUID() const @@ -121,6 +125,11 @@ const LLUUID& LLInventoryObject::getThumbnailUUID() const return mThumbnailUUID; } +bool LLInventoryObject::getIsFavorite() const +{ + return mFavorite; +} + const std::string& LLInventoryObject::getName() const { return mName; @@ -175,6 +184,11 @@ void LLInventoryObject::setThumbnailUUID(const LLUUID& thumbnail_uuid) mThumbnailUUID = thumbnail_uuid; } +void LLInventoryObject::setFavorite(bool favorite) +{ + mFavorite = favorite; +} + void LLInventoryObject::setType(LLAssetType::EType type) { mType = type; @@ -247,6 +261,14 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) + { + setFavorite(metadata["favorite"].asBoolean()); + } + else + { + setFavorite(false); + } } else if(0 == strcmp("name", keyword)) { @@ -735,6 +757,14 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) + { + setFavorite(metadata["favorite"].asBoolean()); + } + else + { + setFavorite(false); + } } else if(0 == strcmp("inv_type", keyword)) { @@ -895,6 +925,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) + { + sd[INV_FAVORITE_LABEL] = mFavorite; + } + U32 mask = mPermissions.getMaskBase(); if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) || (mAssetUUID.isNull())) @@ -974,7 +1009,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) 1 */ continue; - } + } if (i->first == INV_THUMBNAIL_ID_LABEL) { @@ -982,6 +1017,12 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) continue; } + if (i->first == INV_FAVORITE_LABEL) + { + mFavorite = i->second.asBoolean(); + continue; + } + if (i->first == INV_PERMISSIONS_LABEL) { mPermissions = ll_permissions_from_sd(i->second); @@ -1177,6 +1218,11 @@ LLSD LLInventoryCategory::asLLSD() const sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) + { + sd[INV_FAVORITE_LABEL] = mFavorite; + } + return sd; } @@ -1192,6 +1238,10 @@ LLSD LLInventoryCategory::asAISCreateCatLLSD() const { sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) + { + sd[INV_FAVORITE_LABEL] = mFavorite; + } return sd; } @@ -1240,6 +1290,11 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd) mThumbnailUUID = sd[w]; } } + w = INV_FAVORITE_LABEL; + if (sd.has(w)) + { + mFavorite = sd[w].asBoolean(); + } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) { @@ -1362,6 +1417,14 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) + { + setFavorite(metadata["favorite"].asBoolean()); + } + else + { + setFavorite(false); + } } else { @@ -1409,6 +1472,10 @@ LLSD LLInventoryCategory::exportLLSD() const { cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) + { + cat_data[INV_FAVORITE_LABEL] = mFavorite; + } return cat_data; } @@ -1440,6 +1507,10 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID(); } setThumbnailUUID(thumbnail_uuid); + } + if (cat_data.has(INV_FAVORITE_LABEL)) + { + setFavorite(cat_data[INV_FAVORITE_LABEL].asBoolean()); } if (cat_data.has(INV_NAME_LABEL)) { -- cgit v1.3 From 384d694aba523218490ec48c22d97b63acbffd6f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 23 Apr 2024 23:28:58 +0300 Subject: viewer#1300 Inventory favorites context menu --- indra/llinventory/llinventory.cpp | 68 ++++++++++++++++++---- indra/newview/llinventorybridge.cpp | 14 ++++- indra/newview/llinventoryfunctions.cpp | 34 +++++++++++ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llinventorygallerymenu.cpp | 23 ++++++++ .../default/xui/en/menu_gallery_inventory.xml | 16 +++++ .../skins/default/xui/en/menu_inventory.xml | 18 +++++- 7 files changed, 162 insertions(+), 12 deletions(-) (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index cef469e11e..2f701f12a0 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -60,6 +60,7 @@ static const std::string INV_LINKED_ID_LABEL("linked_id"); static const std::string INV_SALE_INFO_LABEL("sale_info"); static const std::string INV_FLAGS_LABEL("flags"); static const std::string INV_CREATION_DATE_LABEL("created_at"); +static const std::string INV_TOGGLED_LABEL("toggled"); // key used by agent-inventory-service static const std::string INV_ASSET_TYPE_LABEL_WS("type_default"); @@ -261,9 +262,18 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) { - setFavorite(metadata["favorite"].asBoolean()); + const LLSD& favorite = metadata["favorite"]; + if (favorite.has("toggled")) + { + setFavorite(favorite["toggled"].asBoolean()); + } + else + { + setFavorite(false); + } } else { @@ -757,9 +767,18 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) { - setFavorite(metadata["favorite"].asBoolean()); + const LLSD& favorite = metadata["favorite"]; + if (favorite.has("toggled")) + { + setFavorite(favorite["toggled"].asBoolean()); + } + else + { + setFavorite(false); + } } else { @@ -927,7 +946,7 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const if (mFavorite) { - sd[INV_FAVORITE_LABEL] = mFavorite; + sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } U32 mask = mPermissions.getMaskBase(); @@ -972,6 +991,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) // TODO - figure out if this should be moved into the noclobber fields above mThumbnailUUID.setNull(); + mFavorite = false; // iterate as map to avoid making unnecessary temp copies of everything LLSD::map_const_iterator i, end; @@ -1019,7 +1039,12 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) if (i->first == INV_FAVORITE_LABEL) { - mFavorite = i->second.asBoolean(); + const LLSD& favorite_map = i->second; + const std::string w = INV_TOGGLED_LABEL; + if (favorite_map.has(w)) + { + mFavorite = favorite_map[w].asBoolean(); + } continue; } @@ -1220,7 +1245,7 @@ LLSD LLInventoryCategory::asLLSD() const if (mFavorite) { - sd[INV_FAVORITE_LABEL] = mFavorite; + sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } return sd; @@ -1234,13 +1259,15 @@ LLSD LLInventoryCategory::asAISCreateCatLLSD() const S8 type = static_cast(mPreferredType); sd[INV_ASSET_TYPE_LABEL_WS] = type; sd[INV_NAME_LABEL] = mName; + if (mThumbnailUUID.notNull()) { sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) { - sd[INV_FAVORITE_LABEL] = mFavorite; + sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } return sd; @@ -1290,10 +1317,16 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd) mThumbnailUUID = sd[w]; } } + mFavorite = false; w = INV_FAVORITE_LABEL; if (sd.has(w)) { - mFavorite = sd[w].asBoolean(); + const LLSD& favorite_map = sd[w]; + w = INV_TOGGLED_LABEL; + if (favorite_map.has(w)) + { + mFavorite = favorite_map[w].asBoolean(); + } } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) @@ -1417,9 +1450,18 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) { - setFavorite(metadata["favorite"].asBoolean()); + const LLSD& favorite = metadata["favorite"]; + if (favorite.has("toggled")) + { + setFavorite(favorite["toggled"].asBoolean()); + } + else + { + setFavorite(false); + } } else { @@ -1474,7 +1516,7 @@ LLSD LLInventoryCategory::exportLLSD() const } if (mFavorite) { - cat_data[INV_FAVORITE_LABEL] = mFavorite; + cat_data[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } return cat_data; @@ -1510,7 +1552,13 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) } if (cat_data.has(INV_FAVORITE_LABEL)) { - setFavorite(cat_data[INV_FAVORITE_LABEL].asBoolean()); + bool favorite = false; + const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL]; + if (favorite_data.has(INV_TOGGLED_LABEL)) + { + favorite = favorite_data[INV_ASSET_ID_LABEL].asBoolean(); + } + setFavorite(favorite); } if (cat_data.has(INV_NAME_LABEL)) { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 93567e6155..17f7f33891 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -852,7 +852,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, disabled_items.push_back(std::string("Copy")); } - if (isAgentInventory() && !single_folder_root) + bool is_agent_inventory = isAgentInventory(); + if (is_agent_inventory && !single_folder_root) { items.push_back(std::string("New folder from selected")); items.push_back(std::string("Subfolder Separator")); @@ -865,6 +866,17 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } } + if (getIsFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else if (is_agent_inventory + && gInventory.getRootFolderID() != mUUID + && !gInventory.isObjectDescendentOf(mUUID, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) + { + items.push_back(std::string("Add to Favorites")); + } + if (obj->getIsLinkType()) { items.push_back(std::string("Find Original")); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index ea0566f5c4..b95d75a782 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2344,6 +2344,26 @@ void ungroup_folder_items(const LLUUID& folder_id) gInventory.notifyObservers(); } +void set_favorite(const LLUUID& obj_id, bool favorite) +{ + LLInventoryObject* obj = gInventory.getObject(obj_id); + if (obj->getIsFavorite() != favorite) + { + LLSD updates; + updates["favorite"] = LLSD().with("toggled", favorite); + LLViewerInventoryCategory* view_folder = dynamic_cast(obj); + if (view_folder) + { + update_inventory_category(obj_id, updates, NULL); + } + LLViewerInventoryItem* view_item = dynamic_cast(obj); + if (view_item) + { + update_inventory_item(obj_id, updates, NULL); + } + } +} + std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id) { if (model) @@ -3322,6 +3342,20 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root ungroup_folder_items(*ids.begin()); } } + else if ("add_to_favorites" == action) + { + for (const LLUUID& id : ids) + { + set_favorite(id, true); + } + } + else if ("remove_from_favorites" == action) + { + for (const LLUUID& id : ids) + { + set_favorite(id, false); + } + } else { std::set::iterator set_iter; diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 5a833eab8c..14038967c6 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -114,6 +114,7 @@ bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_ca std::string get_localized_folder_name(LLUUID cat_uuid); void new_folder_window(const LLUUID& folder_id); void ungroup_folder_items(const LLUUID& folder_id); +void set_favorite(const LLUUID& obj_id, bool favorite); std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id); std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id); std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id); diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 5f4b816b99..6e5d8802a4 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -186,6 +186,20 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata) { ungroup_folder_items(mUUIDs.front()); } + else if ("add_to_favorites" == action) + { + for (const LLUUID& id : mUUIDs) + { + set_favorite(id, true); + } + } + else if ("remove_from_favorites" == action) + { + for (const LLUUID& id : mUUIDs) + { + set_favorite(id, false); + } + } else if ("take_off" == action || "detach" == action) { for (LLUUID& selected_id : mUUIDs) @@ -707,6 +721,15 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men disabled_items.push_back(std::string("New Folder")); disabled_items.push_back(std::string("upload_def")); } + + if (obj->getIsFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else if (is_agent_inventory) + { + items.push_back(std::string("Add to Favorites")); + } } hide_context_entries(*menu, items, disabled_items); diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml index c11f1c88cb..929c626947 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -442,6 +442,22 @@ function="Inventory.DoToSelected" parameter="ungroup_folder_items" /> + + + + + + - + + + + + + + Date: Thu, 2 May 2024 03:05:41 +0300 Subject: Viewer#1301 Implement Inventory Favorites Tab WIP#2 --- indra/llinventory/llinventory.cpp | 26 +++++- indra/newview/llinventorypanel.cpp | 93 ++++++++++++++++++--- indra/newview/llinventorypanel.h | 4 +- indra/newview/llpanelmaininventory.cpp | 2 - .../textures/icons/Inv_Favorite_Star_Content.png | Bin 0 -> 474 bytes .../textures/icons/Inv_Favorite_Star_Full.png | Bin 0 -> 582 bytes indra/newview/skins/default/textures/textures.xml | 2 + .../skins/default/xui/en/floater_preview_trash.xml | 4 +- .../default/xui/en/widgets/folder_view_item.xml | 4 +- .../xui/en/widgets/inbox_folder_view_folder.xml | 4 +- 10 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png create mode 100644 indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 2f701f12a0..0545c6262c 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -874,12 +874,20 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu output_stream << "\t\tparent_id\t" << uuid_str << "\n"; mPermissions.exportLegacyStream(output_stream); - if (mThumbnailUUID.notNull()) + bool needs_metadata = mThumbnailUUID.notNull() || mFavorite; + if (needs_metadata) { // Max length is 255 chars, will have to export differently if it gets more data // Ex: use newline and toNotation (uses {}) for unlimited size LLSD metadata; - metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + if (mThumbnailUUID.notNull()) + { + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + } + if (mFavorite) + { + metadata["favorite"] = LLSD().with("toggled", mFavorite); + } output_stream << "\t\tmetadata\t"; LLSDSerialize::toXML(metadata, output_stream); @@ -1488,11 +1496,21 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n"; output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n"; output_stream << "\t\tname\t" << mName.c_str() << "|\n"; - if (mThumbnailUUID.notNull()) + + bool needs_metadata = mThumbnailUUID.notNull() || mFavorite; + if (needs_metadata) { // Only up to 255 chars LLSD metadata; - metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + if (mThumbnailUUID.notNull()) + { + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + } + if (mFavorite) + { + metadata["favorite"] = LLSD().with("toggled", mFavorite); + } + output_stream << "\t\tmetadata\t"; LLSDSerialize::toXML(metadata, output_stream); output_stream << "|\n"; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index bdf9e87e60..f22ac6f775 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -947,18 +947,7 @@ void LLInventoryPanel::initializeViews(F64 max_time) mBuildViewsEndTime = curent_time + max_time; // init everything - LLUUID root_id = getRootFolderID(); - if (root_id.notNull()) - { - buildNewViews(getRootFolderID()); - } - else - { - // Default case: always add "My Inventory" root first, "Library" root second - // If we run out of time, this still should create root folders - buildNewViews(gInventory.getRootFolderID()); // My Inventory - buildNewViews(gInventory.getLibraryRootFolderID()); // Library - } + initRootContent(); if (mBuildViewsQueue.empty()) { @@ -991,6 +980,22 @@ void LLInventoryPanel::initializeViews(F64 max_time) } } +void LLInventoryPanel::initRootContent() +{ + LLUUID root_id = getRootFolderID(); + if (root_id.notNull()) + { + buildNewViews(getRootFolderID()); + } + else + { + // Default case: always add "My Inventory" root first, "Library" root second + // If we run out of time, this still should create root folders + buildNewViews(gInventory.getRootFolderID()); // My Inventory + buildNewViews(gInventory.getLibraryRootFolderID()); // Library + } +} + LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop) { @@ -1248,6 +1253,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; + //collectInventoryDescendants(id, categories, items); mInventory->lockDirectDescendentArrays(id, categories, items); // Make sure panel won't lock in a loop over existing items if @@ -1348,6 +1354,14 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, return folder_view_item; } + +/*void LLInventoryPanel::collectInventoryDescendants(const LLUUID& id, + LLViewerInventoryCategory::cat_array_t*& categories, + LLViewerInventoryItem::item_array_t*& items); +{ + mInventory->lockDirectDescendentArrays(id, categories, items); +}*/ + // bit of a hack to make sure the inventory is open. void LLInventoryPanel::openStartFolderOrMyInventory() { @@ -2250,6 +2264,9 @@ public: protected: LLInventoryFavoritesItemsPanel(const Params&); friend class LLUICtrlFactory; + + void initRootContent(const LLUUID& id); + void initRootContent() override; }; LLInventoryFavoritesItemsPanel::LLInventoryFavoritesItemsPanel(const Params& params) @@ -2259,6 +2276,58 @@ LLInventoryFavoritesItemsPanel::LLInventoryFavoritesItemsPanel(const Params& par mInvFVBridgeBuilder = &FAVORITES_BUILDER; } +void LLInventoryFavoritesItemsPanel::initRootContent(const LLUUID& id) +{ + LLViewerInventoryCategory::cat_array_t* categories; + LLViewerInventoryItem::item_array_t* items; + mInventory->lockDirectDescendentArrays(id, categories, items); + + if (categories) + { + S32 count = categories->size(); + for (S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = categories->at(i); + if (cat->getPreferredType() == LLFolderType::FT_TRASH) + { + continue; + } + else if (cat->getIsFavorite()) + { + const LLUUID& parent_id = cat->getParentUUID(); + LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID()); // Should be NULL + + buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT); + } + else // Todo: timelimits + { + initRootContent(cat->getUUID()); + } + } + } + + if (items) + { + S32 count = items->size(); + for (S32 i = 0; i < count; ++i) + { + LLViewerInventoryItem* item = items->at(i); + if (item->getIsFavorite() && typedViewsFilter(id, item)) + { + const LLUUID& parent_id = item->getParentUUID(); + LLFolderViewItem* folder_view_item = getItemByID(id); // Should be NULL + + buildViewsTree(item->getUUID(), parent_id, item, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT); + } + } + } +} + +void LLInventoryFavoritesItemsPanel::initRootContent() +{ + initRootContent(gInventory.getRootFolderID()); // My Inventory +} + /************************************************************************/ /* LLInventorySingleFolderPanel */ /************************************************************************/ diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 97300596f9..b6d21ea9a8 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -334,6 +334,7 @@ public: protected: // Builds the UI. Call this once the inventory is usable. void initializeViews(F64 max_time); + virtual void initRootContent(); // Specific inventory colors static bool sColorSetInitialized; @@ -371,7 +372,7 @@ protected: virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge); boost::function& items, BOOL user_action)> mSelectionCallback; -private: +protected: // buildViewsTree does not include some checks and is meant // for recursive use, use buildNewViews() for first call LLFolderViewItem* buildViewsTree(const LLUUID& id, @@ -394,6 +395,7 @@ private: EViewsInitializationState mViewsInitialized; // Whether views have been generated F64 mBuildViewsEndTime; // Stop building views past this timestamp std::deque mBuildViewsQueue; + std::deque mBuildRootContent; }; diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index b1bfd52bc6..c41fedec20 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -199,9 +199,7 @@ BOOL LLPanelMainInventory::postBuild() if (favorites_panel) { favorites_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER)); - favorites_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); LLInventoryFilter& favorites_filter = favorites_panel->getFilter(); - favorites_filter.setFilterFavorites(LLInventoryFilter::FILTER_ONLY_FAVORITES); favorites_filter.setEmptyLookupMessage("InventoryNoMatchingFavorites"); favorites_filter.markDefault(); favorites_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, favorites_panel, _1, _2)); diff --git a/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png new file mode 100644 index 0000000000..bf7ec1599a Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png differ diff --git a/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png new file mode 100644 index 0000000000..916b57f3c5 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index c733d3feaf..7f3b9a8cee 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -304,6 +304,8 @@ with the same filename but different name + + diff --git a/indra/newview/skins/default/xui/en/floater_preview_trash.xml b/indra/newview/skins/default/xui/en/floater_preview_trash.xml index f62e04baf2..ebb5cd9251 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_trash.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_trash.xml @@ -29,8 +29,8 @@ bevel_style="none" scroll.reserve_scroll_corner="false"> Date: Thu, 2 May 2024 21:08:41 +0300 Subject: Viewer#1301 Small cleanup notecards do not need to store 'favorite' flag --- indra/llinventory/llinventory.cpp | 26 ++++---------------------- indra/newview/llinventorypanel.cpp | 9 --------- 2 files changed, 4 insertions(+), 31 deletions(-) (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 0545c6262c..2f701f12a0 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -874,20 +874,12 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu output_stream << "\t\tparent_id\t" << uuid_str << "\n"; mPermissions.exportLegacyStream(output_stream); - bool needs_metadata = mThumbnailUUID.notNull() || mFavorite; - if (needs_metadata) + if (mThumbnailUUID.notNull()) { // Max length is 255 chars, will have to export differently if it gets more data // Ex: use newline and toNotation (uses {}) for unlimited size LLSD metadata; - if (mThumbnailUUID.notNull()) - { - metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); - } - if (mFavorite) - { - metadata["favorite"] = LLSD().with("toggled", mFavorite); - } + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); output_stream << "\t\tmetadata\t"; LLSDSerialize::toXML(metadata, output_stream); @@ -1496,21 +1488,11 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n"; output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n"; output_stream << "\t\tname\t" << mName.c_str() << "|\n"; - - bool needs_metadata = mThumbnailUUID.notNull() || mFavorite; - if (needs_metadata) + if (mThumbnailUUID.notNull()) { // Only up to 255 chars LLSD metadata; - if (mThumbnailUUID.notNull()) - { - metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); - } - if (mFavorite) - { - metadata["favorite"] = LLSD().with("toggled", mFavorite); - } - + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); output_stream << "\t\tmetadata\t"; LLSDSerialize::toXML(metadata, output_stream); output_stream << "|\n"; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index f22ac6f775..3892bfee03 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1253,7 +1253,6 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; - //collectInventoryDescendants(id, categories, items); mInventory->lockDirectDescendentArrays(id, categories, items); // Make sure panel won't lock in a loop over existing items if @@ -1354,14 +1353,6 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, return folder_view_item; } - -/*void LLInventoryPanel::collectInventoryDescendants(const LLUUID& id, - LLViewerInventoryCategory::cat_array_t*& categories, - LLViewerInventoryItem::item_array_t*& items); -{ - mInventory->lockDirectDescendentArrays(id, categories, items); -}*/ - // bit of a hack to make sure the inventory is open. void LLInventoryPanel::openStartFolderOrMyInventory() { -- cgit v1.3 From a420e84f4822d19388241f99a916dacc4d1eab61 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 9 May 2024 23:22:26 +0300 Subject: viewer#1424 Favorites in Appearance floater #2 --- indra/llinventory/llinventory.cpp | 2 +- indra/llui/llaccordionctrltab.h | 2 +- indra/newview/llinventoryfunctions.cpp | 28 ++++++++++++++-- indra/newview/llinventoryobserver.cpp | 29 ++++++++++++++--- indra/newview/llinventoryobserver.h | 18 +++++++++-- indra/newview/lloutfitslist.cpp | 37 +++++++++++++++++++++- indra/newview/lloutfitslist.h | 9 ++++++ .../default/xui/en/menu_gallery_outfit_tab.xml | 32 +++++++++---------- .../skins/default/xui/en/menu_outfit_gear.xml | 12 +++---- .../skins/default/xui/en/menu_outfit_tab.xml | 6 ++++ 10 files changed, 142 insertions(+), 33 deletions(-) (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 2f701f12a0..9b73cbbd74 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -1556,7 +1556,7 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL]; if (favorite_data.has(INV_TOGGLED_LABEL)) { - favorite = favorite_data[INV_ASSET_ID_LABEL].asBoolean(); + favorite = favorite_data[INV_TOGGLED_LABEL].asBoolean(); } setFavorite(favorite); } diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 496c34c38b..c2ddd6f7d1 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -140,7 +140,7 @@ public: S32 notify(const LLSD& info); bool notifyChildren(const LLSD& info); - void draw(); + virtual void draw(); void storeOpenCloseState(); void restoreOpenCloseState(); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 604adea125..123d47b474 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2364,8 +2364,21 @@ void set_favorite(const LLUUID& obj_id, bool favorite) LLInventoryObject* obj = gInventory.getObject(obj_id); if (obj->getIsFavorite() != favorite) { + LLSD val; + if (favorite) + { + val = true; + } // else leave undefined to remove unneeded metadata field + LLSD updates; - updates["favorite"] = LLSD().with("toggled", favorite); + if (favorite) + { + updates["favorite"] = LLSD().with("toggled", true); + } + else + { + updates["favorite"] = LLSD(); + } LLPointer cb = new LLUpdateFavorite(obj_id); @@ -2385,9 +2398,20 @@ void set_favorite(const LLUUID& obj_id, bool favorite) void toggle_favorite(const LLUUID& obj_id) { LLInventoryObject* obj = gInventory.getObject(obj_id); + if (!obj) + { + return; + } LLSD updates; - updates["favorite"] = LLSD().with("toggled", !obj->getIsFavorite()); + if (!obj->getIsFavorite()) + { + updates["favorite"] = LLSD().with("toggled", true); + } + else + { + updates["favorite"] = LLSD(); + } LLPointer cb = new LLUpdateFavorite(obj_id); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 15cd7957a2..4676d8a411 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -749,6 +749,13 @@ void LLInventoryCategoriesObserver::changed(U32 mask) cat_changed = true; } + bool is_favorite = category->getIsFavorite(); + if (cat_data.mIsFavorite != is_favorite) + { + cat_data.mIsFavorite = is_favorite; + cat_changed = true; + } + // If anything has changed above, fire the callback. if (cat_changed) cat_data.mCallback(); @@ -766,6 +773,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN; S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN; bool can_be_added = true; + bool favorite = false; LLUUID thumbnail_id; LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); @@ -779,6 +787,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t // to a category have been made. version = category->getVersion(); thumbnail_id = category->getThumbnailUUID(); + favorite = category->getIsFavorite(); LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; @@ -804,11 +813,11 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t if(init_name_hash) { digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id); - mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents,item_name_hash))); + mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, favorite, cb, version, current_num_known_descendents,item_name_hash))); } else { - mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents))); + mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, favorite, cb, version, current_num_known_descendents))); } } @@ -821,25 +830,37 @@ void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id) } LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( - const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents) + const LLUUID& cat_id, + const LLUUID& thumbnail_id, + bool is_favorite, + callback_t cb, + S32 version, + S32 num_descendents) : mCatID(cat_id) , mCallback(cb) , mVersion(version) , mDescendentsCount(num_descendents) , mThumbnailId(thumbnail_id) + , mIsFavorite(is_favorite) , mIsNameHashInitialized(false) { } LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( - const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash) + const LLUUID& cat_id, + const LLUUID& thumbnail_id, + bool is_favorite, + callback_t cb, S32 version, + S32 num_descendents, + const digest_t& name_hash) : mCatID(cat_id) , mCallback(cb) , mVersion(version) , mDescendentsCount(num_descendents) , mThumbnailId(thumbnail_id) + , mIsFavorite(is_favorite) , mIsNameHashInitialized(true) , mItemNameHash(name_hash) { diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index 6cd630bcd2..7b7d8b06d9 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -277,12 +277,26 @@ protected: typedef LLUUID digest_t; // To clarify the actual usage of this "UUID" struct LLCategoryData { - LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents); - LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash); + LLCategoryData( + const LLUUID& cat_id, + const LLUUID& thumbnail_id, + bool is_favorite, + callback_t cb, + S32 version, + S32 num_descendents); + LLCategoryData( + const LLUUID& cat_id, + const LLUUID& thumbnail_id, + bool is_favorite, + callback_t cb, + S32 version, + S32 num_descendents, + const digest_t& name_hash); callback_t mCallback; S32 mVersion; S32 mDescendentsCount; digest_t mItemNameHash; + bool mIsFavorite; bool mIsNameHashInitialized; LLUUID mCatID; LLUUID mThumbnailId; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index c01e04f88d..ef38edfe3d 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -81,6 +81,9 @@ const outfit_accordion_tab_params& get_accordion_tab_params() { initialized = true; + LLOutfitAccordionCtrlTab::sFavoriteIcon = LLUI::getUIImage("Inv_Favorite_Star_Full"); + LLOutfitAccordionCtrlTab::sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", LLColor4U(255, 255, 255)); + LLXMLNodePtr xmlNode; if (LLUICtrlFactory::getLayeredXMLNode("outfit_accordion_tab.xml", xmlNode)) { @@ -155,6 +158,7 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) tab->setName(name); tab->setTitle(name); + tab->setFavorite(cat->getIsFavorite()); // *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated. tab->setDisplayChildren(false); @@ -426,11 +430,12 @@ void LLOutfitsList::updateChangedCategoryName(LLViewerInventoryCategory *cat, st if (outfits_iter != mOutfitsMap.end()) { // Update tab name with the new category name. - LLAccordionCtrlTab* tab = outfits_iter->second; + LLOutfitAccordionCtrlTab* tab = (LLOutfitAccordionCtrlTab*) outfits_iter->second; if (tab) { tab->setName(name); tab->setTitle(name); + tab->setFavorite(cat->getIsFavorite()); } } } @@ -1382,6 +1387,16 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility() LLOutfitListGearMenuBase::onUpdateItemsVisibility(); } + +LLUIImage* LLOutfitAccordionCtrlTab::sFavoriteIcon; +LLUIColor LLOutfitAccordionCtrlTab::sFgColor; + +void LLOutfitAccordionCtrlTab::draw() +{ + LLAccordionCtrlTab::draw(); + drawFavoriteIcon(); +} + BOOL LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) { if (y >= getLocalRect().getHeight() - getHeaderHeight()) @@ -1402,4 +1417,24 @@ BOOL LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) return LLAccordionCtrlTab::handleToolTip(x, y, mask); } + +void LLOutfitAccordionCtrlTab::drawFavoriteIcon() +{ + if (!mIsFavorite) + { + return; + } + static LLUICachedControl draw_star("InventoryFavoritesUseStar", true); + if (!draw_star) + { + return; + } + + const S32 PAD = 2; + const S32 image_size = 18; + + gl_draw_scaled_image( + getRect().getWidth() - image_size - PAD, getRect().getHeight() - image_size - PAD, + image_size, image_size, sFavoriteIcon->getImage(), sFgColor); +} // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 86702cedfb..8975ac09d1 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -221,8 +221,14 @@ public: Params() : cat_id("cat_id") {} }; + virtual void draw(); virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); + void setFavorite(bool is_favorite) { mIsFavorite = is_favorite; } + + static LLUIImage* sFavoriteIcon; + static LLUIColor sFgColor; + protected: LLOutfitAccordionCtrlTab(const LLOutfitAccordionCtrlTab::Params &p) : LLAccordionCtrlTab(p), @@ -230,7 +236,10 @@ public: {} friend class LLUICtrlFactory; + void drawFavoriteIcon(); + LLUUID mFolderID; + bool mIsFavorite = false; }; /** * @class LLOutfitsList diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml index 77de521154..fb68193006 100755 --- a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml @@ -50,24 +50,24 @@ function="Outfit.Thumbnail" /> + label="Add to favorites" + layout="topleft" + name="favorites_add"> - + function="Outfit.OnVisible" + parameter="favorites_add" /> + - - - + + + - + @@ -63,9 +63,9 @@ label="Remove from favorite outfits" layout="topleft" name="favorites_remove"> - + 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 070efe9d78..0d45e7c95c 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml @@ -53,6 +53,9 @@ label="Add to favorites" layout="topleft" name="favorites_add"> + @@ -60,6 +63,9 @@ label="Remove from favorites" layout="topleft" name="favorites_remove"> + -- cgit v1.3