EXT-8577 FIXED Context menu items for multi-attachments

Changes:
* Implemented bulk-add from My Appearance SP.
* Made sure there's no memleak when you click Wear/Attach in the in-world object context menu
  and the callback isn't invoked (because e.g. avatar fails to get close enough to the object).
  I stated that in comments.

Reviewed by Seraph at https://codereview.productengine.com/secondlife/r/844/

--HG--
branch : product-engine
meow-7.2.2
Vadim Savchuk 2010-08-09 18:10:36 +03:00
parent fe96d9a474
commit 554d543b02
5 changed files with 58 additions and 17 deletions

View File

@ -5950,7 +5950,8 @@ void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointA
delta = delta * 0.5f;
walkToSpot -= delta;
CallbackData* user_data = new CallbackData(attachment_point, mReplace); // *TODO: leak if the callback isn't called?
// The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak.
CallbackData* user_data = new CallbackData(attachment_point, mReplace);
gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance);
gAgentCamera.clearFocusObject();
}

View File

@ -5641,6 +5641,15 @@ BOOL LLVOAvatar::canAttachMoreObjects() const
return (getNumAttachments() < MAX_AGENT_ATTACHMENTS);
}
//-----------------------------------------------------------------------------
// canAttachMoreObjects()
// Returns true if we can attach <n> more objects.
//-----------------------------------------------------------------------------
BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const
{
return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;
}
//-----------------------------------------------------------------------------
// lazyAttach()
//-----------------------------------------------------------------------------

View File

@ -687,6 +687,7 @@ public:
void rebuildHUD();
void resetHUDAttachments();
BOOL canAttachMoreObjects() const;
BOOL canAttachMoreObjects(U32 n) const;
protected:
U32 getNumAttachments() const; // O(N), not O(1)

View File

@ -869,7 +869,7 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
setMenuItemVisible(menu, "wear_wear", n_already_worn == 0 && n_worn == 0 && can_be_worn);
setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0);
setMenuItemVisible(menu, "wear_add", wear_add_visible);
setMenuItemEnabled(menu, "wear_add", n_items == 1 && canAddWearable(ids.front()));
setMenuItemEnabled(menu, "wear_add", canAddWearables(ids));
setMenuItemVisible(menu, "wear_replace", n_worn == 0 && n_already_worn != 0 && can_be_worn);
//visible only when one item selected and this item is worn
setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1);
@ -978,31 +978,61 @@ void LLWearableItemsList::ContextMenu::createNewWearable(const LLUUID& item_id)
LLAgentWearables::createWearable(item->getWearableType(), true);
}
// Can we wear another wearable of the given item's wearable type?
// Returns true if all the given objects and clothes can be added.
// static
bool LLWearableItemsList::ContextMenu::canAddWearable(const LLUUID& item_id)
bool LLWearableItemsList::ContextMenu::canAddWearables(const uuid_vec_t& item_ids)
{
// TODO: investigate wearables may not be loaded at this point EXT-8231
LLViewerInventoryItem* item = gInventory.getItem(item_id);
if (!item)
U32 n_objects = 0;
boost::unordered_map<LLWearableType::EType, U32> clothes_by_type;
// Count given clothes (by wearable type) and objects.
for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it)
{
LLViewerInventoryItem* item = gInventory.getItem(*it);
if (!item)
{
return false;
}
if (item->getType() == LLAssetType::AT_OBJECT)
{
++n_objects;
}
else if (item->getType() == LLAssetType::AT_CLOTHING)
{
++clothes_by_type[item->getWearableType()];
}
else
{
llwarns << "Unexpected wearable type" << llendl;
return false;
}
}
// Check whether we can add all the objects.
if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects))
{
return false;
}
if (item->getType() == LLAssetType::AT_OBJECT)
// Check whether we can add all the clothes.
boost::unordered_map<LLWearableType::EType, U32>::const_iterator m_it;
for (m_it = clothes_by_type.begin(); m_it != clothes_by_type.end(); ++m_it)
{
// *TODO: is this the right check?
return isAgentAvatarValid() && gAgentAvatarp->canAttachMoreObjects();
LLWearableType::EType w_type = m_it->first;
U32 n_clothes = m_it->second;
U32 wearable_count = gAgentWearables.getWearableCount(w_type);
if ((wearable_count + n_clothes) > LLAgentWearables::MAX_CLOTHING_PER_TYPE)
{
return false;
}
}
if (item->getType() != LLAssetType::AT_CLOTHING)
{
return false;
}
U32 wearable_count = gAgentWearables.getWearableCount(item->getWearableType());
return wearable_count < LLAgentWearables::MAX_CLOTHING_PER_TYPE;
return true;
}
// EOF

View File

@ -431,7 +431,7 @@ public:
static void setMenuItemEnabled(LLContextMenu* menu, const std::string& name, bool val);
static void updateMask(U32& mask, LLAssetType::EType at);
static void createNewWearable(const LLUUID& item_id);
static bool canAddWearable(const LLUUID& item_id);
static bool canAddWearables(const uuid_vec_t& item_ids);
LLWearableItemsList* mParent;
};