summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llagentwearables.cpp24
-rw-r--r--indra/newview/llagentwearables.h2
-rw-r--r--indra/newview/llappearancemgr.cpp8
-rw-r--r--indra/newview/llappearancemgr.h6
-rw-r--r--indra/newview/llpanelwearing.cpp251
-rw-r--r--indra/newview/llpanelwearing.h33
-rw-r--r--indra/newview/llviewermenu.h1
-rw-r--r--indra/newview/skins/default/xui/en/menu_wearing_tab.xml7
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_wearing.xml41
9 files changed, 373 insertions, 0 deletions
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 8a65aa6a89..718c1c2251 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1373,6 +1373,30 @@ void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array
// LL_INFOS() << "remove " << remove_count << " add " << add_count << LL_ENDL;
}
+std::vector<LLViewerObject*> LLAgentWearables::getTempAttachments()
+{
+ llvo_vec_t temp_attachs;
+ if (isAgentAvatarValid())
+ {
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); iter != gAgentAvatarp->mAttachmentPoints.end();)
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ LLViewerObject *objectp = (*attachment_iter);
+ if (objectp && objectp->isTempAttachment())
+ {
+ temp_attachs.push_back(objectp);
+ }
+ }
+ }
+ }
+ return temp_attachs;
+}
+
void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove)
{
if (!isAgentAvatarValid()) return;
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 1004482020..b27698fd8f 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -185,6 +185,8 @@ public:
static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array);
static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array);
+ static llvo_vec_t getTempAttachments();
+
//--------------------------------------------------------------------
// Signals
//--------------------------------------------------------------------
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index a1d9786321..4a4361e94b 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -3916,6 +3916,10 @@ void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)
LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL;
mAttachmentInvLinkEnabled = val;
}
+boost::signals2::connection LLAppearanceMgr::setAttachmentsChangedCallback(attachments_changed_callback_t cb)
+{
+ return mAttachmentsChangeSignal.connect(cb);
+}
void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
{
@@ -3942,6 +3946,8 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
LLAttachmentsMgr::instance().onAttachmentArrived(item_id);
+
+ mAttachmentsChangeSignal();
}
void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
@@ -3962,6 +3968,8 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
{
//LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL;
}
+
+ mAttachmentsChangeSignal();
}
BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 7069da7352..07ae5fba86 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -225,6 +225,10 @@ public:
void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; }
std::string getAppearanceServiceURL() const;
+ typedef boost::function<void ()> attachments_changed_callback_t;
+ typedef boost::signals2::signal<void ()> attachments_changed_signal_t;
+ boost::signals2::connection setAttachmentsChangedCallback(attachments_changed_callback_t cb);
+
private:
@@ -268,6 +272,8 @@ private:
LLTimer mInFlightTimer;
static bool mActive;
+ attachments_changed_signal_t mAttachmentsChangeSignal;
+
std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer;
// Set of temp attachment UUIDs that should be removed
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index d0353259a5..796372ba04 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -30,13 +30,19 @@
#include "lltoggleablemenu.h"
+#include "llagent.h"
+#include "llaccordionctrl.h"
+#include "llaccordionctrltab.h"
#include "llappearancemgr.h"
#include "llfloatersidepanelcontainer.h"
#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
#include "llmenubutton.h"
+#include "llscrolllistctrl.h"
#include "llviewermenu.h"
+#include "llviewerregion.h"
#include "llwearableitemslist.h"
#include "llsdserialize.h"
#include "llclipboard.h"
@@ -146,11 +152,47 @@ protected:
menu->setItemVisible("detach", allow_detach);
menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach);
menu->setItemVisible("show_original", mUUIDs.size() == 1);
+ menu->setItemVisible("edit_item", FALSE);
}
};
//////////////////////////////////////////////////////////////////////////
+class LLTempAttachmentsContextMenu : public LLListContextMenu
+{
+public:
+ LLTempAttachmentsContextMenu(LLPanelWearing* panel_wearing)
+ : mPanelWearing(panel_wearing)
+ {}
+protected:
+ /* virtual */ LLContextMenu* createMenu()
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+
+ registrar.add("Wearing.EditItem", boost::bind(&LLPanelWearing::onEditAttachment, mPanelWearing));
+ registrar.add("Wearing.Detach", boost::bind(&LLPanelWearing::onRemoveAttachment, mPanelWearing));
+ LLContextMenu* menu = createFromFile("menu_wearing_tab.xml");
+
+ updateMenuItemsVisibility(menu);
+
+ return menu;
+ }
+
+ void updateMenuItemsVisibility(LLContextMenu* menu)
+ {
+ menu->setItemVisible("take_off", FALSE);
+ menu->setItemVisible("detach", TRUE);
+ menu->setItemVisible("edit_outfit_separator", TRUE);
+ menu->setItemVisible("show_original", FALSE);
+ menu->setItemVisible("edit_item", TRUE);
+ menu->setItemVisible("edit", FALSE);
+ }
+
+ LLPanelWearing* mPanelWearing;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
std::string LLPanelAppearanceTab::sFilterSubString = LLStringUtil::null;
static LLPanelInjector<LLPanelWearing> t_panel_wearing("panel_wearing");
@@ -159,30 +201,47 @@ LLPanelWearing::LLPanelWearing()
: LLPanelAppearanceTab()
, mCOFItemsList(NULL)
, mIsInitialized(false)
+ , mAttachmentsChangedConnection()
{
mCategoriesObserver = new LLInventoryCategoriesObserver();
mGearMenu = new LLWearingGearMenu(this);
mContextMenu = new LLWearingContextMenu();
+ mAttachmentsMenu = new LLTempAttachmentsContextMenu(this);
}
LLPanelWearing::~LLPanelWearing()
{
delete mGearMenu;
delete mContextMenu;
+ delete mAttachmentsMenu;
if (gInventory.containsObserver(mCategoriesObserver))
{
gInventory.removeObserver(mCategoriesObserver);
}
delete mCategoriesObserver;
+
+ if (mAttachmentsChangedConnection.connected())
+ {
+ mAttachmentsChangedConnection.disconnect();
+ }
}
BOOL LLPanelWearing::postBuild()
{
+ mAccordionCtrl = getChild<LLAccordionCtrl>("wearables_accordion");
+ mWearablesTab = getChild<LLAccordionCtrlTab>("tab_wearables");
+ mAttachmentsTab = getChild<LLAccordionCtrlTab>("tab_temp_attachments");
+ mAttachmentsTab->setDropDownStateChangedCallback(boost::bind(&LLPanelWearing::onAccordionTabStateChanged, this));
+
mCOFItemsList = getChild<LLWearableItemsList>("cof_items_list");
mCOFItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onWearableItemsListRightClick, this, _1, _2, _3));
+ mTempItemsList = getChild<LLScrollListCtrl>("temp_attachments_list");
+ mTempItemsList->setFgUnselectedColor(LLColor4::white);
+ mTempItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onTempAttachmentsListRightClick, this, _1, _2, _3));
+
LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
menu_gear_btn->setMenu(mGearMenu->getMenu());
@@ -223,6 +282,44 @@ void LLPanelWearing::onOpen(const LLSD& /*info*/)
}
}
+void LLPanelWearing::draw()
+{
+ if (mUpdateTimer.getStarted() && (mUpdateTimer.getElapsedTimeF32() > 0.1))
+ {
+ mUpdateTimer.stop();
+ updateAttachmentsList();
+ }
+ LLPanel::draw();
+}
+
+void LLPanelWearing::onAccordionTabStateChanged()
+{
+ if(mAttachmentsTab->isExpanded())
+ {
+ startUpdateTimer();
+ mAttachmentsChangedConnection = LLAppearanceMgr::instance().setAttachmentsChangedCallback(boost::bind(&LLPanelWearing::startUpdateTimer, this));
+ }
+ else
+ {
+ if (mAttachmentsChangedConnection.connected())
+ {
+ mAttachmentsChangedConnection.disconnect();
+ }
+ }
+}
+
+void LLPanelWearing::startUpdateTimer()
+{
+ if (!mUpdateTimer.getStarted())
+ {
+ mUpdateTimer.start();
+ }
+ else
+ {
+ mUpdateTimer.reset();
+ }
+}
+
// virtual
void LLPanelWearing::setFilterSubString(const std::string& string)
{
@@ -251,6 +348,124 @@ bool LLPanelWearing::isActionEnabled(const LLSD& userdata)
return false;
}
+void LLPanelWearing::updateAttachmentsList()
+{
+ std::vector<LLViewerObject*> attachs = LLAgentWearables::getTempAttachments();
+ mTempItemsList->deleteAllItems();
+ mAttachmentsMap.clear();
+ if(!attachs.empty())
+ {
+ if(!populateAttachmentsList())
+ {
+ requestAttachmentDetails();
+ }
+ }
+ else
+ {
+ std::string no_attachments = getString("no_attachments");
+ LLSD row;
+ row["columns"][0]["column"] = "text";
+ row["columns"][0]["value"] = no_attachments;
+ row["columns"][0]["font"] = "SansSerifBold";
+ mTempItemsList->addElement(row);
+ }
+}
+
+bool LLPanelWearing::populateAttachmentsList(bool update)
+{
+ bool populated = true;
+ if(mTempItemsList)
+ {
+ mTempItemsList->deleteAllItems();
+ mAttachmentsMap.clear();
+ std::vector<LLViewerObject*> attachs = LLAgentWearables::getTempAttachments();
+
+ std::string icon_name = LLInventoryIcon::getIconName(LLAssetType::AT_OBJECT, LLInventoryType::IT_OBJECT);
+ for (std::vector<LLViewerObject*>::iterator iter = attachs.begin();
+ iter != attachs.end(); ++iter)
+ {
+ LLViewerObject *attachment = *iter;
+ LLSD row;
+ row["id"] = attachment->getID();
+ row["columns"][0]["column"] = "icon";
+ row["columns"][0]["type"] = "icon";
+ row["columns"][0]["value"] = icon_name;
+ row["columns"][1]["column"] = "text";
+ if(mObjectNames.count(attachment->getID()) && !mObjectNames[attachment->getID()].empty())
+ {
+ row["columns"][1]["value"] = mObjectNames[attachment->getID()];
+ }
+ else if(update)
+ {
+ row["columns"][1]["value"] = attachment->getID();
+ populated = false;
+ }
+ else
+ {
+ row["columns"][1]["value"] = "Loading...";
+ populated = false;
+ }
+ mTempItemsList->addElement(row);
+ mAttachmentsMap[attachment->getID()] = attachment;
+ }
+ }
+ return populated;
+}
+
+void LLPanelWearing::requestAttachmentDetails()
+{
+ LLSD body;
+ std::string url = gAgent.getRegion()->getCapability("AttachmentResources");
+ if (!url.empty())
+ {
+ LLCoros::instance().launch("LLPanelWearing::getAttachmentLimitsCoro",
+ boost::bind(&LLPanelWearing::getAttachmentLimitsCoro, this, url));
+ }
+}
+
+void LLPanelWearing::getAttachmentLimitsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL;
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ setAttachmentDetails(result);
+}
+
+
+void LLPanelWearing::setAttachmentDetails(LLSD content)
+{
+ mObjectNames.clear();
+ S32 number_attachments = content["attachments"].size();
+ for(int i = 0; i < number_attachments; i++)
+ {
+ S32 number_objects = content["attachments"][i]["objects"].size();
+ for(int j = 0; j < number_objects; j++)
+ {
+ LLUUID task_id = content["attachments"][i]["objects"][j]["id"].asUUID();
+ std::string name = content["attachments"][i]["objects"][j]["name"].asString();
+ mObjectNames[task_id] = name;
+ }
+ }
+ if(!mObjectNames.empty())
+ {
+ populateAttachmentsList(true);
+ }
+}
+
boost::signals2::connection LLPanelWearing::setSelectionChangeCallback(commit_callback_t cb)
{
if (!mCOFItemsList) return boost::signals2::connection();
@@ -270,6 +485,20 @@ void LLPanelWearing::onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y)
mContextMenu->show(ctrl, selected_uuids, x, y);
}
+void LLPanelWearing::onTempAttachmentsListRightClick(LLUICtrl* ctrl, S32 x, S32 y)
+{
+ LLScrollListCtrl* list = dynamic_cast<LLScrollListCtrl*>(ctrl);
+ if (!list) return;
+ list->selectItemAt(x, y, MASK_NONE);
+ uuid_vec_t selected_uuids;
+
+ if(list->getCurrentID().notNull())
+ {
+ selected_uuids.push_back(list->getCurrentID());
+ mAttachmentsMenu->show(ctrl, selected_uuids, x, y);
+ }
+}
+
bool LLPanelWearing::hasItemSelected()
{
return mCOFItemsList->getSelectedItem() != NULL;
@@ -280,6 +509,28 @@ void LLPanelWearing::getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const
mCOFItemsList->getSelectedUUIDs(selected_uuids);
}
+void LLPanelWearing::onEditAttachment()
+{
+ LLScrollListItem* item = mTempItemsList->getFirstSelected();
+ if (item)
+ {
+ LLSelectMgr::getInstance()->deselectAll();
+ LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]);
+ handle_object_edit();
+ }
+}
+
+void LLPanelWearing::onRemoveAttachment()
+{
+ LLScrollListItem* item = mTempItemsList->getFirstSelected();
+ if (item)
+ {
+ LLSelectMgr::getInstance()->deselectAll();
+ LLSelectMgr::getInstance()->selectObjectAndFamily(mAttachmentsMap[item->getUUID()]);
+ LLSelectMgr::getInstance()->sendDropAttachment();
+ }
+}
+
void LLPanelWearing::copyToClipboard()
{
std::string text;
diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h
index 9a212b3cca..c5cb79092a 100644
--- a/indra/newview/llpanelwearing.h
+++ b/indra/newview/llpanelwearing.h
@@ -31,9 +31,14 @@
// newview
#include "llpanelappearancetab.h"
+#include "llselectmgr.h"
+#include "lltimer.h"
+class LLAccordionCtrl;
+class LLAccordionCtrlTab;
class LLInventoryCategoriesObserver;
class LLListContextMenu;
+class LLScrollListCtrl;
class LLWearableItemsList;
class LLWearingGearMenu;
@@ -52,6 +57,8 @@ public:
/*virtual*/ BOOL postBuild();
+ /*virtual*/ void draw();
+
/*virtual*/ void onOpen(const LLSD& info);
/*virtual*/ void setFilterSubString(const std::string& string);
@@ -62,17 +69,43 @@ public:
/*virtual*/ void copyToClipboard();
+ void startUpdateTimer();
+ void updateAttachmentsList();
+
boost::signals2::connection setSelectionChangeCallback(commit_callback_t cb);
bool hasItemSelected();
+ bool populateAttachmentsList(bool update = false);
+ void onAccordionTabStateChanged();
+ void setAttachmentDetails(LLSD content);
+ void requestAttachmentDetails();
+ void onEditAttachment();
+ void onRemoveAttachment();
+
private:
void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
+ void onTempAttachmentsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
+
+ void getAttachmentLimitsCoro(std::string url);
LLInventoryCategoriesObserver* mCategoriesObserver;
LLWearableItemsList* mCOFItemsList;
+ LLScrollListCtrl* mTempItemsList;
LLWearingGearMenu* mGearMenu;
LLListContextMenu* mContextMenu;
+ LLListContextMenu* mAttachmentsMenu;
+
+ LLAccordionCtrlTab* mWearablesTab;
+ LLAccordionCtrlTab* mAttachmentsTab;
+ LLAccordionCtrl* mAccordionCtrl;
+
+ std::map<LLUUID, LLViewerObject*> mAttachmentsMap;
+
+ std::map<LLUUID, std::string> mObjectNames;
+
+ boost::signals2::connection mAttachmentsChangedConnection;
+ LLFrameTimer mUpdateTimer;
bool mIsInitialized;
};
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index 2f9bf7f714..a553bb79a2 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -108,6 +108,7 @@ void handle_look_at_selection(const LLSD& param);
void handle_zoom_to_object(LLUUID object_id);
void handle_object_return();
void handle_object_delete();
+void handle_object_edit();
void handle_buy_land();
diff --git a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml
index 44b2727671..75c1de24aa 100644
--- a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml
+++ b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml
@@ -28,6 +28,13 @@
function="Wearing.Edit" />
</menu_item_call>
<menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="edit_item">
+ <on_click
+ function="Wearing.EditItem" />
+ </menu_item_call>
+ <menu_item_call
label="Show Original"
layout="topleft"
name="show_original">
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
index d85b778db2..42a7974316 100644
--- a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
@@ -9,6 +9,26 @@
name="Wearing"
top="0"
width="312">
+<panel.string
+ name="no_attachments">
+ No attachments worn.
+ </panel.string>
+ <accordion
+ fit_parent="true"
+ follows="all"
+ height="400"
+ layout="topleft"
+ left="0"
+ single_expansion="true"
+ top="0"
+ name="wearables_accordion"
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ width="309">
+ <accordion_tab
+ layout="topleft"
+ name="tab_wearables"
+ title="Wearables">
<wearable_items_list
follows="all"
height="400"
@@ -20,6 +40,27 @@
top="0"
width="309"
worn_indication_enabled="false" />
+ </accordion_tab>
+ <accordion_tab
+ layout="topleft"
+ name="tab_temp_attachments"
+ title="Temporary attachments">
+ <scroll_list
+ draw_heading="false"
+ left="3"
+ width="309"
+ height="400"
+ follows="all"
+ name="temp_attachments_list">
+ <scroll_list.columns
+ name="icon"
+ width="15" />
+ <scroll_list.columns
+ name="text"
+ width="210" />
+ </scroll_list>
+ </accordion_tab>
+ </accordion>
<panel
background_visible="true"
follows="bottom|left|right"