From b8e0c16ab1eb3cdd1d11e869bd3fd6196de51d4b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 21 Jun 2024 17:42:45 +0300 Subject: Add Appearance listener --- indra/newview/CMakeLists.txt | 2 + indra/newview/llappearancelistener.cpp | 110 +++++++++++++++++++++ indra/newview/llappearancelistener.h | 44 +++++++++ indra/newview/llappearancemgr.cpp | 28 +++++- indra/newview/llappearancemgr.h | 2 +- indra/newview/llviewermenu.cpp | 4 +- indra/newview/scripts/lua/LLAppearance.lua | 25 +++++ .../scripts/lua/luafloater_outfits_list.xml | 21 ++++ indra/newview/scripts/lua/test_outfits_list.lua | 27 +++++ 9 files changed, 255 insertions(+), 8 deletions(-) create mode 100644 indra/newview/llappearancelistener.cpp create mode 100644 indra/newview/llappearancelistener.h create mode 100644 indra/newview/scripts/lua/LLAppearance.lua create mode 100644 indra/newview/scripts/lua/luafloater_outfits_list.xml create mode 100644 indra/newview/scripts/lua/test_outfits_list.lua diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ab65d71916..4e7e072289 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -95,6 +95,7 @@ set(viewer_SOURCE_FILES llagentwearables.cpp llanimstatelabels.cpp llappcorehttp.cpp + llappearancelistener.cpp llappearancemgr.cpp llappviewer.cpp llappviewerlistener.cpp @@ -760,6 +761,7 @@ set(viewer_HEADER_FILES llanimstatelabels.h llappcorehttp.h llappearance.h + llappearancelistener.h llappearancemgr.h llappviewer.h llappviewerlistener.h diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp new file mode 100644 index 0000000000..2d5ff6bee4 --- /dev/null +++ b/indra/newview/llappearancelistener.cpp @@ -0,0 +1,110 @@ +/** + * @file llappearancelistener.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llappearancelistener.h" + +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "stringize.h" + +LLAppearanceListener::LLAppearanceListener() + : LLEventAPI("LLAppearance", + "API to wear a specified outfit and wear/remove individual items") +{ + add("wearOutfit", + "Wear outfit by folder id: [folder_id]" + "When [\"append\"] is true, outfit will be added to COF\n" + "otherwise it will replace current oufit", + &LLAppearanceListener::wearOutfit, + llsd::map("folder_id", LLSD(), "append", LLSD())); + + add("wearOutfitByName", + "Wear outfit by folder name: [folder_name]" + "When [\"append\"] is true, outfit will be added to COF\n" + "otherwise it will replace current oufit", + &LLAppearanceListener::wearOutfitByName, + llsd::map("folder_name", LLSD(), "append", LLSD())); + + add("getOutfitsList", + "Return the table of Outfits(id and name) which are send to the script", + &LLAppearanceListener::getOutfitsList); +} + + +void LLAppearanceListener::wearOutfit(LLSD const &data) +{ + Response response(LLSD(), data); + LLViewerInventoryCategory* cat = gInventory.getCategory(data["folder_id"].asUUID()); + if (!cat) + { + response.error(stringize("Couldn't find outfit ", data["folder_id"].asUUID())); + return; + } + if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + { + response.error(stringize("Can't wear system folder ", data["folder_id"].asUUID())); + return; + } + bool append = data["append"].asBoolean(); + bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat->getUUID()) : LLAppearanceMgr::instance().getCanReplaceCOF(cat->getUUID()); + if (!can_wear) + { + std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; + response.error(stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID())); + return; + } + LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); +} + +void LLAppearanceListener::wearOutfitByName(LLSD const &data) +{ + Response response(LLSD(), data); + std::string error_msg; + if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), data["append"].asBoolean(), error_msg)) + { + response.error(error_msg); + } +} + +void LLAppearanceListener::getOutfitsList(LLSD const &data) +{ + Response response(LLSD(), data); + const LLUUID outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLIsType is_category(LLAssetType::AT_CATEGORY); + gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category); + + LLSD outfits_data; + for (const LLPointer &cat : cat_array) + { + outfits_data[cat->getUUID().asString()] = cat->getName(); + } + response["outfits"] = outfits_data; +} diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h new file mode 100644 index 0000000000..8448b2ede9 --- /dev/null +++ b/indra/newview/llappearancelistener.h @@ -0,0 +1,44 @@ +/** + * @file llappearancelistener.h + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLAPPEARANCELISTENER_H +#define LL_LLAPPEARANCELISTENER_H + +#include "lleventapi.h" + +class LLAppearanceListener : public LLEventAPI +{ +public: + LLAppearanceListener(); + +private: + void wearOutfit(LLSD const &data); + void wearOutfitByName(LLSD const &data); + void getOutfitsList(LLSD const &data); +}; + +#endif // LL_LLAPPEARANCELISTENER_H + diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 30f07a873b..19b81f5a79 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" +#include "llappearancelistener.h" #include "llappearancemgr.h" #include "llattachmentsmgr.h" #include "llcommandhandler.h" @@ -71,6 +72,8 @@ #pragma warning (disable:4702) #endif +LLAppearanceListener sAppearanceListener; + namespace { const S32 BAKE_RETRY_MAX_COUNT = 5; @@ -2900,8 +2903,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } -// FIXME do we really want to search entire inventory for matching name? -void LLAppearanceMgr::wearOutfitByName(const std::string& name) +bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std::string& error_msg) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2936,13 +2938,29 @@ void LLAppearanceMgr::wearOutfitByName(const std::string& name) if(cat) { - LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); + bool is_system_folder = LLFolderType::lookupIsProtectedType(cat->getPreferredType()); + if (is_system_folder) + { + error_msg = stringize("Can't wear system folder ", std::quoted(name)); + return false; + } + bool can_wear = append ? getCanAddToCOF(cat->getUUID()) : getCanReplaceCOF(cat->getUUID()); + if (!can_wear) + { + std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; + error_msg = stringize(msg, std::quoted(name), " , id: ", cat->getUUID()); + LL_WARNS() << error_msg << LL_ENDL; + return false; + } + LLAppearanceMgr::wearInventoryCategory(cat, copy_items, append); } else { - LL_WARNS() << "Couldn't find outfit " < Character > Animation Speed view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); diff --git a/indra/newview/scripts/lua/LLAppearance.lua b/indra/newview/scripts/lua/LLAppearance.lua new file mode 100644 index 0000000000..ec7a25197f --- /dev/null +++ b/indra/newview/scripts/lua/LLAppearance.lua @@ -0,0 +1,25 @@ +leap = require 'leap' + +local LLAppearance = {} + +function LLAppearance.addOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) +end + +function LLAppearance.replaceOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) +end + +function LLAppearance.addOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) +end + +function LLAppearance.replaceOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) +end + +function LLAppearance.getOutfitsList() + return leap.request('LLAppearance', {op='getOutfitsList'})['outfits'] +end + +return LLAppearance diff --git a/indra/newview/scripts/lua/luafloater_outfits_list.xml b/indra/newview/scripts/lua/luafloater_outfits_list.xml new file mode 100644 index 0000000000..1f6505cb8d --- /dev/null +++ b/indra/newview/scripts/lua/luafloater_outfits_list.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua new file mode 100644 index 0000000000..5875fd51da --- /dev/null +++ b/indra/newview/scripts/lua/test_outfits_list.lua @@ -0,0 +1,27 @@ +local Floater = require 'Floater' +local LLAppearance = require 'LLAppearance' +local startup = require 'startup' + +local flt = Floater:new( + "luafloater_outfits_list.xml", + {outfits_list = {"double_click"}}) + +function flt:post_build(event_data) + local outfits_map = LLAppearance.getOutfitsList() + local action_data = {} + action_data.action = "add_list_element" + action_data.ctrl_name = "outfits_list" + local outfits = {} + for uuid, name in pairs(outfits_map) do + table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) + end + action_data.value = outfits + self:post(action_data) +end + +function flt:double_click_outfits_list(event_data) + LLAppearance.replaceOutfit(event_data.value) +end + +startup.wait('STATE_STARTED') +flt:show() -- cgit v1.2.3 From eb6d24e531aa5faa251b7aaf8b13c62f06708696 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 25 Jun 2024 14:51:53 +0300 Subject: Add wear/detach actions to Appearance listener; update example script --- indra/llui/llluafloater.cpp | 31 +++++++- indra/newview/llappearancelistener.cpp | 50 +++++++++++- indra/newview/llappearancelistener.h | 3 + indra/newview/llwearableitemslist.cpp | 13 +-- indra/newview/llwearableitemslist.h | 9 +++ indra/newview/scripts/lua/LLAppearance.lua | 25 ------ .../scripts/lua/luafloater_outfits_list.xml | 36 ++++++++- indra/newview/scripts/lua/require/LLAppearance.lua | 37 +++++++++ indra/newview/scripts/lua/test_outfits_list.lua | 93 ++++++++++++++++++++-- 9 files changed, 250 insertions(+), 47 deletions(-) delete mode 100644 indra/newview/scripts/lua/LLAppearance.lua create mode 100644 indra/newview/scripts/lua/require/LLAppearance.lua diff --git a/indra/llui/llluafloater.cpp b/indra/llui/llluafloater.cpp index e584a67a00..b08508bf9b 100644 --- a/indra/llui/llluafloater.cpp +++ b/indra/llui/llluafloater.cpp @@ -101,6 +101,15 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : } }, requiredParams); + mDispatchListener.add("clear_list", "", [this](const LLSD &event) + { + LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); + if(ctrl) + { + ctrl->deleteAllItems(); + } + }, llsd::map("ctrl_name", LLSD())); + mDispatchListener.add("add_text", "", [this](const LLSD &event) { LLTextEditor *editor = getChild(event["ctrl_name"].asString()); @@ -111,15 +120,35 @@ LLLuaFloater::LLLuaFloater(const LLSD &key) : } }, requiredParams); + mDispatchListener.add("set_label", "", [this](const LLSD &event) + { + LLButton *btn = getChild(event["ctrl_name"].asString()); + if (btn) + { + btn->setLabel((event["value"]).asString()); + } + }, requiredParams); + mDispatchListener.add("set_title", "", [this](const LLSD &event) { setTitle(event["value"].asString()); }, llsd::map("value", LLSD())); - + mDispatchListener.add("get_value", "", [ctrl_lookup](const LLSD &event) { return ctrl_lookup(event, [](LLUICtrl *ctrl, const LLSD &event) { return llsd::map("value", ctrl->getValue()); }); }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD())); + + mDispatchListener.add("get_selected_id", "", [this](const LLSD &event) + { + LLScrollListCtrl *ctrl = getChild(event["ctrl_name"].asString()); + if (!ctrl) + { + LL_WARNS("LuaFloater") << "Control not found: " << event["ctrl_name"] << LL_ENDL; + return LLSD(); + } + return llsd::map("value", ctrl->getCurrentID()); + }, llsd::map("ctrl_name", LLSD(), "reqid", LLSD())); } LLLuaFloater::~LLLuaFloater() diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 2d5ff6bee4..11037a0078 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -30,6 +30,7 @@ #include "llappearancemgr.h" #include "llinventoryfunctions.h" #include "stringize.h" +#include "llwearableitemslist.h" LLAppearanceListener::LLAppearanceListener() : LLEventAPI("LLAppearance", @@ -49,9 +50,23 @@ LLAppearanceListener::LLAppearanceListener() &LLAppearanceListener::wearOutfitByName, llsd::map("folder_name", LLSD(), "append", LLSD())); + add("wearItem", + "Wear item by item id: [item_id]", + &LLAppearanceListener::wearItem, + llsd::map("item_id", LLSD(), "replace", LLSD())); + + add("detachItem", + "Detach item by item id: [item_id]", + &LLAppearanceListener::detachItem, + llsd::map("item_id", LLSD())); + add("getOutfitsList", - "Return the table of Outfits(id and name) which are send to the script", + "Return the table with Outfits info(id and name)", &LLAppearanceListener::getOutfitsList); + + add("getOutfitItems", + "Return the table of items(id and name) inside specified outfit folder", + &LLAppearanceListener::getOutfitItems); } @@ -90,6 +105,16 @@ void LLAppearanceListener::wearOutfitByName(LLSD const &data) } } +void LLAppearanceListener::wearItem(LLSD const &data) +{ + LLAppearanceMgr::instance().wearItemOnAvatar(data["item_id"].asUUID(), true, data["replace"].asBoolean()); +} + +void LLAppearanceListener::detachItem(LLSD const &data) +{ + LLAppearanceMgr::instance().removeItemFromAvatar(data["item_id"].asUUID()); +} + void LLAppearanceListener::getOutfitsList(LLSD const &data) { Response response(LLSD(), data); @@ -108,3 +133,26 @@ void LLAppearanceListener::getOutfitsList(LLSD const &data) } response["outfits"] = outfits_data; } + +void LLAppearanceListener::getOutfitItems(LLSD const &data) +{ + Response response(LLSD(), data); + LLUUID outfit_id(data["outfit_id"].asUUID()); + LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); + if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + response.error(stringize("Can't find outfit folder with id: ", outfit_id.asString())); + } + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, LLFindOutfitItems()); + + LLSD items_data; + for (const LLPointer &it : item_array) + { + items_data[it->getUUID().asString()] = it->getName(); + } + + response["items"] = items_data; +} diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h index 8448b2ede9..00553c072f 100644 --- a/indra/newview/llappearancelistener.h +++ b/indra/newview/llappearancelistener.h @@ -37,7 +37,10 @@ public: private: void wearOutfit(LLSD const &data); void wearOutfitByName(LLSD const &data); + void wearItem(LLSD const &data); + void detachItem(LLSD const &data); void getOutfitsList(LLSD const &data); + void getOutfitItems(LLSD const &data); }; #endif // LL_LLAPPEARANCELISTENER_H diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 676164fcc6..e122cc0360 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -33,7 +33,6 @@ #include "llagentwearables.h" #include "llappearancemgr.h" -#include "llinventoryfunctions.h" #include "llinventoryicon.h" #include "llgesturemgr.h" #include "lltransutil.h" @@ -41,14 +40,6 @@ #include "llviewermenu.h" #include "llvoavatarself.h" -class LLFindOutfitItems : public LLInventoryCollectFunctor -{ -public: - LLFindOutfitItems() {} - virtual ~LLFindOutfitItems() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -}; bool LLFindOutfitItems::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -60,10 +51,10 @@ bool LLFindOutfitItems::operator()(LLInventoryCategory* cat, || (item->getType() == LLAssetType::AT_OBJECT) || (item->getType() == LLAssetType::AT_GESTURE)) { - return TRUE; + return true; } } - return FALSE; + return false; } ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index 80e211ad6b..a24679961f 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -32,6 +32,7 @@ #include "llsingleton.h" // newview +#include "llinventoryfunctions.h" #include "llinventoryitemslist.h" #include "llinventorylistitem.h" #include "lllistcontextmenu.h" @@ -505,4 +506,12 @@ protected: LLWearableType::EType mMenuWearableType; }; +class LLFindOutfitItems : public LLInventoryCollectFunctor +{ + public: + LLFindOutfitItems() {} + virtual ~LLFindOutfitItems() {} + virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item); +}; + #endif //LL_LLWEARABLEITEMSLIST_H diff --git a/indra/newview/scripts/lua/LLAppearance.lua b/indra/newview/scripts/lua/LLAppearance.lua deleted file mode 100644 index ec7a25197f..0000000000 --- a/indra/newview/scripts/lua/LLAppearance.lua +++ /dev/null @@ -1,25 +0,0 @@ -leap = require 'leap' - -local LLAppearance = {} - -function LLAppearance.addOutfit(folder) - leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) -end - -function LLAppearance.replaceOutfit(folder) - leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) -end - -function LLAppearance.addOutfitByName(folder) - leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) -end - -function LLAppearance.replaceOutfitByName(folder) - leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) -end - -function LLAppearance.getOutfitsList() - return leap.request('LLAppearance', {op='getOutfitsList'})['outfits'] -end - -return LLAppearance diff --git a/indra/newview/scripts/lua/luafloater_outfits_list.xml b/indra/newview/scripts/lua/luafloater_outfits_list.xml index 1f6505cb8d..8cab864308 100644 --- a/indra/newview/scripts/lua/luafloater_outfits_list.xml +++ b/indra/newview/scripts/lua/luafloater_outfits_list.xml @@ -1,15 +1,15 @@ + width="325"> + + + diff --git a/indra/newview/scripts/lua/require/LLAppearance.lua b/indra/newview/scripts/lua/require/LLAppearance.lua new file mode 100644 index 0000000000..165bb6d06f --- /dev/null +++ b/indra/newview/scripts/lua/require/LLAppearance.lua @@ -0,0 +1,37 @@ +leap = require 'leap' + +local LLAppearance = {} + +function LLAppearance.addOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) +end + +function LLAppearance.replaceOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) +end + +function LLAppearance.addOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) +end + +function LLAppearance.replaceOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) +end + +function LLAppearance.wearItem(item_id, replace) + leap.send('LLAppearance', {op='wearItem', replace = replace, item_id=item_id}) +end + +function LLAppearance.detachItem(item_id) + leap.send('LLAppearance', {op='detachItem', item_id=item_id}) +end + +function LLAppearance.getOutfitsList() + return leap.request('LLAppearance', {op='getOutfitsList'})['outfits'] +end + +function LLAppearance.getOutfitItems(id) + return leap.request('LLAppearance', {op='getOutfitItems', outfit_id = id})['items'] +end + +return LLAppearance diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua index 5875fd51da..dd5f914402 100644 --- a/indra/newview/scripts/lua/test_outfits_list.lua +++ b/indra/newview/scripts/lua/test_outfits_list.lua @@ -1,26 +1,107 @@ local Floater = require 'Floater' local LLAppearance = require 'LLAppearance' local startup = require 'startup' +local inspect = require 'inspect' + +local SHOW_OUTFITS = true +local SELECTED_OUTFIT_ID = {} +local DATA_MAP = {} + +local wearables_lbl = 'Show wearables' +local outfits_lbl = 'Show outfits' +local replace_cof_lbl = 'Replace COF' +local add_cof_lbl = 'Add to COF' +local outfits_title = 'Outfits' +local wear_lbl = 'Wear item' +local detach_lbl = 'Detach item' local flt = Floater:new( "luafloater_outfits_list.xml", {outfits_list = {"double_click"}}) -function flt:post_build(event_data) - local outfits_map = LLAppearance.getOutfitsList() +function get_selected_id() + return flt:request({action="get_selected_id", ctrl_name='outfits_list'}).value +end + +function populate_list() + if SHOW_OUTFITS then + DATA_MAP = LLAppearance.getOutfitsList() + else + DATA_MAP = LLAppearance.getOutfitItems(SELECTED_OUTFIT_ID) + end + local action_data = {} action_data.action = "add_list_element" action_data.ctrl_name = "outfits_list" local outfits = {} - for uuid, name in pairs(outfits_map) do + for uuid, name in pairs(DATA_MAP) do table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) end action_data.value = outfits - self:post(action_data) + flt:post(action_data) +end + +function set_label(btn_name, value) + flt:post({action="set_label", ctrl_name=btn_name, value=value}) +end + +function set_enabled(btn_name, value) + flt:post({action="set_enabled", ctrl_name=btn_name, value=value}) +end + +function update_labels() + if SHOW_OUTFITS then + set_label('select_btn', wearables_lbl) + set_label('replace_btn', replace_cof_lbl) + set_label('add_btn', add_cof_lbl) + + set_enabled('select_btn', false) + flt:post({action="set_title", value=outfits_title}) + else + set_label('select_btn', outfits_lbl) + set_label('replace_btn', wear_lbl) + set_label('add_btn', detach_lbl) + + set_enabled('select_btn', true) + flt:post({action="set_title", value=DATA_MAP[SELECTED_OUTFIT_ID]}) + end + + set_enabled('replace_btn', false) + set_enabled('add_btn', false) +end + +function flt:post_build(event_data) + populate_list() +end + +function flt:commit_replace_btn(event_data) + if SHOW_OUTFITS then + LLAppearance.replaceOutfit(get_selected_id()) + else + LLAppearance.wearItem(get_selected_id(), false) + end +end + +function flt:commit_add_btn(event_data) + if SHOW_OUTFITS then + LLAppearance.addOutfit(get_selected_id()) + else + LLAppearance.detachItem(get_selected_id()) + end +end + +function flt:commit_select_btn(event_data) + SHOW_OUTFITS = not SHOW_OUTFITS + SELECTED_OUTFIT_ID = get_selected_id() + update_labels() + self:post({action="clear_list", ctrl_name='outfits_list'}) + populate_list() end -function flt:double_click_outfits_list(event_data) - LLAppearance.replaceOutfit(event_data.value) +function flt:commit_outfits_list(event_data) + set_enabled('replace_btn', true) + set_enabled('add_btn', true) + set_enabled('select_btn', true) end startup.wait('STATE_STARTED') -- cgit v1.2.3 From 07f0f12bcbe864177a145b074c2739eaf08f2c5c Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 1 Jul 2024 13:02:49 +0300 Subject: Move error strings to strings.xml; pass wearable type and is_worn flag for outfit items --- indra/newview/llappearancelistener.cpp | 20 +++++++++++++------- indra/newview/llappearancemgr.cpp | 9 +++++---- indra/newview/scripts/lua/test_outfits_list.lua | 8 +++++++- indra/newview/skins/default/xui/en/strings.xml | 4 ++++ 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 11037a0078..3db2c64b78 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -29,8 +29,9 @@ #include "llappearancemgr.h" #include "llinventoryfunctions.h" -#include "stringize.h" +#include "lltransutil.h" #include "llwearableitemslist.h" +#include "stringize.h" LLAppearanceListener::LLAppearanceListener() : LLEventAPI("LLAppearance", @@ -65,7 +66,7 @@ LLAppearanceListener::LLAppearanceListener() &LLAppearanceListener::getOutfitsList); add("getOutfitItems", - "Return the table of items(id and name) inside specified outfit folder", + "Return the table of items with info(id : name, wearable_type, is_worn) inside specified outfit folder", &LLAppearanceListener::getOutfitItems); } @@ -76,19 +77,19 @@ void LLAppearanceListener::wearOutfit(LLSD const &data) LLViewerInventoryCategory* cat = gInventory.getCategory(data["folder_id"].asUUID()); if (!cat) { - response.error(stringize("Couldn't find outfit ", data["folder_id"].asUUID())); + response.error(stringize(LLTrans::getString("OutfitNotFound"), data["folder_id"].asUUID())); return; } if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { - response.error(stringize("Can't wear system folder ", data["folder_id"].asUUID())); + response.error(stringize(LLTrans::getString("SystemFolderNotWorn"), data["folder_id"].asUUID())); return; } bool append = data["append"].asBoolean(); bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat->getUUID()) : LLAppearanceMgr::instance().getCanReplaceCOF(cat->getUUID()); if (!can_wear) { - std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; + std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); response.error(stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID())); return; } @@ -141,7 +142,7 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) { - response.error(stringize("Can't find outfit folder with id: ", outfit_id.asString())); + response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString())); } LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; @@ -151,7 +152,12 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLSD items_data; for (const LLPointer &it : item_array) { - items_data[it->getUUID().asString()] = it->getName(); + LLSD info; + info["name"] = it->getName(); + info["wearable_type"] = LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE); + info["is_worn"] = get_is_item_worn(it); + + items_data[it->getUUID().asString()] = info; } response["items"] = items_data; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 19b81f5a79..3d13f8afc8 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -49,6 +49,7 @@ #include "lloutfitslist.h" #include "llselectmgr.h" #include "llsidepanelappearance.h" +#include "lltransutil.h" #include "llviewerobjectlist.h" #include "llvoavatar.h" #include "llvoavatarself.h" @@ -2941,14 +2942,14 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std bool is_system_folder = LLFolderType::lookupIsProtectedType(cat->getPreferredType()); if (is_system_folder) { - error_msg = stringize("Can't wear system folder ", std::quoted(name)); + error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), std::quoted(name)); return false; } bool can_wear = append ? getCanAddToCOF(cat->getUUID()) : getCanReplaceCOF(cat->getUUID()); if (!can_wear) { - std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; - error_msg = stringize(msg, std::quoted(name), " , id: ", cat->getUUID()); + std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); + error_msg = stringize(msg, std::quoted(name), ", id: ", cat->getUUID()); LL_WARNS() << error_msg << LL_ENDL; return false; } @@ -2956,7 +2957,7 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std } else { - error_msg = stringize("Couldn't find outfit ", std::quoted(name)); + error_msg = stringize(LLTrans::getString("OutfitNotFound"), std::quoted(name)); LL_WARNS() << error_msg << LL_ENDL; return false; } diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua index dd5f914402..1011029f34 100644 --- a/indra/newview/scripts/lua/test_outfits_list.lua +++ b/indra/newview/scripts/lua/test_outfits_list.lua @@ -34,7 +34,13 @@ function populate_list() action_data.action = "add_list_element" action_data.ctrl_name = "outfits_list" local outfits = {} - for uuid, name in pairs(DATA_MAP) do + for uuid, info in pairs(DATA_MAP) do + name = {} + if SHOW_OUTFITS then + name = info + else + name = info.name + end table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) end action_data.value = outfits diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 76a2660dbb..492b29fbc7 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -4028,6 +4028,10 @@ Please check http://status.secondlifegrid.net to see if there is a known problem Delete selected item? There are no items in this outfit + + + + Select an editor by setting the environment variable LL_SCRIPT_EDITOR or the ExternalEditor setting. -- cgit v1.2.3 From 3961bac0ef705775883a4b37f2b6a84e41b82c05 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Mon, 1 Jul 2024 14:47:52 +0300 Subject: build fix --- indra/newview/llappearancelistener.cpp | 5 +++-- indra/newview/llappearancemgr.cpp | 13 +++++++++++-- indra/newview/llappearancemgr.h | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 3db2c64b78..b29eb48a1b 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -100,7 +100,7 @@ void LLAppearanceListener::wearOutfitByName(LLSD const &data) { Response response(LLSD(), data); std::string error_msg; - if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), data["append"].asBoolean(), error_msg)) + if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), error_msg, data["append"].asBoolean())) { response.error(error_msg); } @@ -147,7 +147,8 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; - gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, LLFindOutfitItems()); + LLFindOutfitItems collector = LLFindOutfitItems(); + gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); LLSD items_data; for (const LLPointer &it : item_array) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 3d13f8afc8..e4a545a55b 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2904,7 +2904,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } -bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std::string& error_msg) +bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& error_msg, bool append) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2950,7 +2950,6 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std { std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); error_msg = stringize(msg, std::quoted(name), ", id: ", cat->getUUID()); - LL_WARNS() << error_msg << LL_ENDL; return false; } LLAppearanceMgr::wearInventoryCategory(cat, copy_items, append); @@ -2958,6 +2957,16 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std else { error_msg = stringize(LLTrans::getString("OutfitNotFound"), std::quoted(name)); + return false; + } + return true; +} + +bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append) +{ + std::string error_msg; + if(!wearOutfitByName(name, error_msg, append)) + { LL_WARNS() << error_msg << LL_ENDL; return false; } diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index d7b6cd5a61..adc783be5a 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -59,7 +59,8 @@ public: void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append); - bool wearOutfitByName(const std::string &name, bool append = false, std::string &error_msg = std::string()); + bool wearOutfitByName(const std::string &name, std::string &error_msg, bool append = false); + bool wearOutfitByName(const std::string &name, bool append = false); void changeOutfit(bool proceed, const LLUUID& category, bool append); void replaceCurrentOutfit(const LLUUID& new_outfit); void renameOutfit(const LLUUID& outfit_id); -- cgit v1.2.3 From a877e3a0994a19d522e77d6781844341197dd6dc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 3 Jul 2024 14:05:25 -0400 Subject: Use llsd::toMap() to return LLSD maps from "LLAppearance" listener. --- indra/newview/llappearancelistener.cpp | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index b29eb48a1b..2a3133433a 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -127,12 +127,9 @@ void LLAppearanceListener::getOutfitsList(LLSD const &data) LLIsType is_category(LLAssetType::AT_CATEGORY); gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category); - LLSD outfits_data; - for (const LLPointer &cat : cat_array) - { - outfits_data[cat->getUUID().asString()] = cat->getName(); - } - response["outfits"] = outfits_data; + response["outfits"] = llsd::toMap(cat_array, + [](const LLPointer &cat) + { return std::make_pair(cat->getUUID().asString(), cat->getName()); }); } void LLAppearanceListener::getOutfitItems(LLSD const &data) @@ -150,16 +147,14 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLFindOutfitItems collector = LLFindOutfitItems(); gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); - LLSD items_data; - for (const LLPointer &it : item_array) - { - LLSD info; - info["name"] = it->getName(); - info["wearable_type"] = LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE); - info["is_worn"] = get_is_item_worn(it); - - items_data[it->getUUID().asString()] = info; - } - - response["items"] = items_data; + response["items"] = llsd::toMap(item_array, + [](const LLPointer &it) + { + return std::make_pair( + it->getUUID().asString(), + llsd::map( + "name", it->getName(), + "wearable_type", LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE), + "is_worn", get_is_item_worn(it))); + }); } -- cgit v1.2.3 From ece0f4eb566af937d724f60f934beb6dfcb4d493 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 5 Jul 2024 16:03:51 +0300 Subject: clean up and rename demo script --- indra/newview/llappearancelistener.cpp | 93 +++++++++-------- indra/newview/llappearancelistener.h | 5 +- indra/newview/llappearancemgr.cpp | 28 ++++- indra/newview/llappearancemgr.h | 1 + indra/newview/llwearableitemslist.h | 3 +- indra/newview/scripts/lua/require/LLAppearance.lua | 28 ++--- indra/newview/scripts/lua/test_LLAppearance.lua | 114 +++++++++++++++++++++ indra/newview/scripts/lua/test_outfits_list.lua | 114 --------------------- 8 files changed, 205 insertions(+), 181 deletions(-) create mode 100644 indra/newview/scripts/lua/test_LLAppearance.lua delete mode 100644 indra/newview/scripts/lua/test_outfits_list.lua diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 2a3133433a..75eaf29186 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -38,28 +38,20 @@ LLAppearanceListener::LLAppearanceListener() "API to wear a specified outfit and wear/remove individual items") { add("wearOutfit", - "Wear outfit by folder id: [folder_id]" + "Wear outfit by folder id: [folder_id] OR by folder name: [folder_name]\n" "When [\"append\"] is true, outfit will be added to COF\n" "otherwise it will replace current oufit", - &LLAppearanceListener::wearOutfit, - llsd::map("folder_id", LLSD(), "append", LLSD())); + &LLAppearanceListener::wearOutfit); - add("wearOutfitByName", - "Wear outfit by folder name: [folder_name]" - "When [\"append\"] is true, outfit will be added to COF\n" - "otherwise it will replace current oufit", - &LLAppearanceListener::wearOutfitByName, - llsd::map("folder_name", LLSD(), "append", LLSD())); - - add("wearItem", - "Wear item by item id: [item_id]", - &LLAppearanceListener::wearItem, - llsd::map("item_id", LLSD(), "replace", LLSD())); + add("wearItems", + "Wear items by id: [items_id]", + &LLAppearanceListener::wearItems, + llsd::map("items_id", LLSD(), "replace", LLSD())); - add("detachItem", - "Detach item by item id: [item_id]", - &LLAppearanceListener::detachItem, - llsd::map("item_id", LLSD())); + add("detachItems", + "Detach items by id: [items_id]", + &LLAppearanceListener::detachItems, + llsd::map("items_id", LLSD())); add("getOutfitsList", "Return the table with Outfits info(id and name)", @@ -74,46 +66,61 @@ LLAppearanceListener::LLAppearanceListener() void LLAppearanceListener::wearOutfit(LLSD const &data) { Response response(LLSD(), data); - LLViewerInventoryCategory* cat = gInventory.getCategory(data["folder_id"].asUUID()); - if (!cat) + if (!data.has("folder_id") && !data.has("folder_name")) { - response.error(stringize(LLTrans::getString("OutfitNotFound"), data["folder_id"].asUUID())); - return; + return response.error("Either [folder_id] or [folder_name] is required"); } - if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + + std::string error_msg; + bool result(false); + bool append = data.has("append") ? data["append"].asBoolean() : false; + if (data.has("folder_id")) { - response.error(stringize(LLTrans::getString("SystemFolderNotWorn"), data["folder_id"].asUUID())); - return; + result = LLAppearanceMgr::instance().wearOutfit(data["folder_id"].asUUID(), error_msg, append); } - bool append = data["append"].asBoolean(); - bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat->getUUID()) : LLAppearanceMgr::instance().getCanReplaceCOF(cat->getUUID()); - if (!can_wear) + else { - std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); - response.error(stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID())); - return; + result = LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), error_msg, append); } - LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); -} -void LLAppearanceListener::wearOutfitByName(LLSD const &data) -{ - Response response(LLSD(), data); - std::string error_msg; - if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), error_msg, data["append"].asBoolean())) + if (!result) { response.error(error_msg); } } -void LLAppearanceListener::wearItem(LLSD const &data) +void LLAppearanceListener::wearItems(LLSD const &data) { - LLAppearanceMgr::instance().wearItemOnAvatar(data["item_id"].asUUID(), true, data["replace"].asBoolean()); + if (data["items_id"].isArray()) + { + uuid_vec_t ids; + for (const auto &id : llsd::inArray(data["items_id"])) + { + ids.push_back(id); + } + LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, data["replace"].asBoolean()); + } + else + { + LLAppearanceMgr::instance().wearItemOnAvatar(data["items_id"].asUUID(), true, data["replace"].asBoolean()); + } } -void LLAppearanceListener::detachItem(LLSD const &data) +void LLAppearanceListener::detachItems(LLSD const &data) { - LLAppearanceMgr::instance().removeItemFromAvatar(data["item_id"].asUUID()); + if (data["items_id"].isArray()) + { + uuid_vec_t ids; + for (const auto &id : llsd::inArray(data["items_id"])) + { + ids.push_back(id); + } + LLAppearanceMgr::instance().removeItemsFromAvatar(ids); + } + else + { + LLAppearanceMgr::instance().removeItemFromAvatar(data["items_id"].asUUID()); + } } void LLAppearanceListener::getOutfitsList(LLSD const &data) @@ -139,7 +146,7 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) { - response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString())); + return response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString())); } LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h index 00553c072f..04c5eac2eb 100644 --- a/indra/newview/llappearancelistener.h +++ b/indra/newview/llappearancelistener.h @@ -36,9 +36,8 @@ public: private: void wearOutfit(LLSD const &data); - void wearOutfitByName(LLSD const &data); - void wearItem(LLSD const &data); - void detachItem(LLSD const &data); + void wearItems(LLSD const &data); + void detachItems(LLSD const &data); void getOutfitsList(LLSD const &data); void getOutfitItems(LLSD const &data); }; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index e4a545a55b..7a34006323 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2939,8 +2939,8 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& err if(cat) { - bool is_system_folder = LLFolderType::lookupIsProtectedType(cat->getPreferredType()); - if (is_system_folder) + // don't allow wearing a system folder + if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), std::quoted(name)); return false; @@ -2962,6 +2962,30 @@ bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& err return true; } +bool LLAppearanceMgr::wearOutfit(const LLUUID &cat_id, std::string &error_msg, bool append) +{ + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + if (!cat) + { + error_msg = stringize(LLTrans::getString("OutfitNotFound"), cat_id); + return false; + } + if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + { + error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), cat_id); + return false; + } + bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat_id) : LLAppearanceMgr::instance().getCanReplaceCOF(cat_id); + if (!can_wear) + { + std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced"); + error_msg = stringize(msg, std::quoted(cat->getName()), " , id: ", cat_id); + return false; + } + LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); + return true; +} + bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append) { std::string error_msg; diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index adc783be5a..b795494f94 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -59,6 +59,7 @@ public: void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append); + bool wearOutfit(const LLUUID &cat_id, std::string &error_msg, bool append = false); bool wearOutfitByName(const std::string &name, std::string &error_msg, bool append = false); bool wearOutfitByName(const std::string &name, bool append = false); void changeOutfit(bool proceed, const LLUUID& category, bool append); diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index a24679961f..15033f5e9a 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -506,9 +506,8 @@ protected: LLWearableType::EType mMenuWearableType; }; -class LLFindOutfitItems : public LLInventoryCollectFunctor +struct LLFindOutfitItems : public LLInventoryCollectFunctor { - public: LLFindOutfitItems() {} virtual ~LLFindOutfitItems() {} virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item); diff --git a/indra/newview/scripts/lua/require/LLAppearance.lua b/indra/newview/scripts/lua/require/LLAppearance.lua index 165bb6d06f..f533d22daf 100644 --- a/indra/newview/scripts/lua/require/LLAppearance.lua +++ b/indra/newview/scripts/lua/require/LLAppearance.lua @@ -1,29 +1,23 @@ -leap = require 'leap' +local leap = require 'leap' local LLAppearance = {} -function LLAppearance.addOutfit(folder) - leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) +function LLAppearance.wearOutfit(folder, action) + action = action or 'add' + leap.request('LLAppearance', {op='wearOutfit', append = (action == 'add'), folder_id=folder}) end -function LLAppearance.replaceOutfit(folder) - leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) +function LLAppearance.wearOutfitByName(folder, action) + action = action or 'add' + leap.request('LLAppearance', {op='wearOutfit', append = (action == 'add'), folder_name=folder}) end -function LLAppearance.addOutfitByName(folder) - leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) +function LLAppearance.wearItems(items_id, replace) + leap.send('LLAppearance', {op='wearItems', replace = replace, items_id=items_id}) end -function LLAppearance.replaceOutfitByName(folder) - leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) -end - -function LLAppearance.wearItem(item_id, replace) - leap.send('LLAppearance', {op='wearItem', replace = replace, item_id=item_id}) -end - -function LLAppearance.detachItem(item_id) - leap.send('LLAppearance', {op='detachItem', item_id=item_id}) +function LLAppearance.detachItems(items_id) + leap.send('LLAppearance', {op='detachItems', items_id=items_id}) end function LLAppearance.getOutfitsList() diff --git a/indra/newview/scripts/lua/test_LLAppearance.lua b/indra/newview/scripts/lua/test_LLAppearance.lua new file mode 100644 index 0000000000..5ddd9f15ff --- /dev/null +++ b/indra/newview/scripts/lua/test_LLAppearance.lua @@ -0,0 +1,114 @@ +local Floater = require 'Floater' +local LLAppearance = require 'LLAppearance' +local startup = require 'startup' +local inspect = require 'inspect' + +local SHOW_OUTFITS = true +local SELECTED_OUTFIT_ID = {} +local DATA_MAP = {} + +local wearables_lbl = 'Show wearables' +local outfits_lbl = 'Show outfits' +local replace_cof_lbl = 'Replace COF' +local add_cof_lbl = 'Add to COF' +local outfits_title = 'Outfits' +local wear_lbl = 'Wear item' +local detach_lbl = 'Detach item' + +local flt = Floater:new( + "luafloater_outfits_list.xml", + {outfits_list = {"double_click"}}) + +function get_selected_id() + return flt:request({action="get_selected_id", ctrl_name='outfits_list'}).value +end + +function populate_list() + if SHOW_OUTFITS then + DATA_MAP = LLAppearance.getOutfitsList() + else + DATA_MAP = LLAppearance.getOutfitItems(SELECTED_OUTFIT_ID) + end + + local action_data = {} + action_data.action = "add_list_element" + action_data.ctrl_name = "outfits_list" + local outfits = {} + for uuid, info in pairs(DATA_MAP) do + name = {} + if SHOW_OUTFITS then + name = info + else + name = info.name + end + table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) + end + action_data.value = outfits + flt:post(action_data) +end + +function set_label(btn_name, value) + flt:post({action="set_label", ctrl_name=btn_name, value=value}) +end + +function set_enabled(btn_name, value) + flt:post({action="set_enabled", ctrl_name=btn_name, value=value}) +end + +function update_labels() + if SHOW_OUTFITS then + set_label('select_btn', wearables_lbl) + set_label('replace_btn', replace_cof_lbl) + set_label('add_btn', add_cof_lbl) + + set_enabled('select_btn', false) + flt:post({action="set_title", value=outfits_title}) + else + set_label('select_btn', outfits_lbl) + set_label('replace_btn', wear_lbl) + set_label('add_btn', detach_lbl) + + set_enabled('select_btn', true) + flt:post({action="set_title", value=DATA_MAP[SELECTED_OUTFIT_ID]}) + end + + set_enabled('replace_btn', false) + set_enabled('add_btn', false) +end + +function flt:post_build(event_data) + populate_list() +end + +function flt:commit_replace_btn(event_data) + if SHOW_OUTFITS then + LLAppearance.wearOutfit(get_selected_id(), 'replace') + else + LLAppearance.wearItems(get_selected_id(), false) + end +end + +function flt:commit_add_btn(event_data) + if SHOW_OUTFITS then + LLAppearance.wearOutfit(get_selected_id(), 'add') + else + LLAppearance.detachItems(get_selected_id()) + end +end + +function flt:commit_select_btn(event_data) + SHOW_OUTFITS = not SHOW_OUTFITS + SELECTED_OUTFIT_ID = get_selected_id() + update_labels() + self:post({action="clear_list", ctrl_name='outfits_list'}) + populate_list() +end + +function flt:commit_outfits_list(event_data) + set_enabled('replace_btn', true) + set_enabled('add_btn', true) + set_enabled('select_btn', true) +end + +startup.wait('STATE_STARTED') +flt:show() diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua deleted file mode 100644 index 1011029f34..0000000000 --- a/indra/newview/scripts/lua/test_outfits_list.lua +++ /dev/null @@ -1,114 +0,0 @@ -local Floater = require 'Floater' -local LLAppearance = require 'LLAppearance' -local startup = require 'startup' -local inspect = require 'inspect' - -local SHOW_OUTFITS = true -local SELECTED_OUTFIT_ID = {} -local DATA_MAP = {} - -local wearables_lbl = 'Show wearables' -local outfits_lbl = 'Show outfits' -local replace_cof_lbl = 'Replace COF' -local add_cof_lbl = 'Add to COF' -local outfits_title = 'Outfits' -local wear_lbl = 'Wear item' -local detach_lbl = 'Detach item' - -local flt = Floater:new( - "luafloater_outfits_list.xml", - {outfits_list = {"double_click"}}) - -function get_selected_id() - return flt:request({action="get_selected_id", ctrl_name='outfits_list'}).value -end - -function populate_list() - if SHOW_OUTFITS then - DATA_MAP = LLAppearance.getOutfitsList() - else - DATA_MAP = LLAppearance.getOutfitItems(SELECTED_OUTFIT_ID) - end - - local action_data = {} - action_data.action = "add_list_element" - action_data.ctrl_name = "outfits_list" - local outfits = {} - for uuid, info in pairs(DATA_MAP) do - name = {} - if SHOW_OUTFITS then - name = info - else - name = info.name - end - table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) - end - action_data.value = outfits - flt:post(action_data) -end - -function set_label(btn_name, value) - flt:post({action="set_label", ctrl_name=btn_name, value=value}) -end - -function set_enabled(btn_name, value) - flt:post({action="set_enabled", ctrl_name=btn_name, value=value}) -end - -function update_labels() - if SHOW_OUTFITS then - set_label('select_btn', wearables_lbl) - set_label('replace_btn', replace_cof_lbl) - set_label('add_btn', add_cof_lbl) - - set_enabled('select_btn', false) - flt:post({action="set_title", value=outfits_title}) - else - set_label('select_btn', outfits_lbl) - set_label('replace_btn', wear_lbl) - set_label('add_btn', detach_lbl) - - set_enabled('select_btn', true) - flt:post({action="set_title", value=DATA_MAP[SELECTED_OUTFIT_ID]}) - end - - set_enabled('replace_btn', false) - set_enabled('add_btn', false) -end - -function flt:post_build(event_data) - populate_list() -end - -function flt:commit_replace_btn(event_data) - if SHOW_OUTFITS then - LLAppearance.replaceOutfit(get_selected_id()) - else - LLAppearance.wearItem(get_selected_id(), false) - end -end - -function flt:commit_add_btn(event_data) - if SHOW_OUTFITS then - LLAppearance.addOutfit(get_selected_id()) - else - LLAppearance.detachItem(get_selected_id()) - end -end - -function flt:commit_select_btn(event_data) - SHOW_OUTFITS = not SHOW_OUTFITS - SELECTED_OUTFIT_ID = get_selected_id() - update_labels() - self:post({action="clear_list", ctrl_name='outfits_list'}) - populate_list() -end - -function flt:commit_outfits_list(event_data) - set_enabled('replace_btn', true) - set_enabled('add_btn', true) - set_enabled('select_btn', true) -end - -startup.wait('STATE_STARTED') -flt:show() -- cgit v1.2.3