summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llagentwearables.cpp26
-rw-r--r--indra/newview/llagentwearables.h1
-rw-r--r--indra/newview/llappearancemgr.cpp71
-rw-r--r--indra/newview/llappearancemgr.h6
-rw-r--r--indra/newview/llcofwearables.cpp61
-rw-r--r--indra/newview/llfloaterland.cpp2
-rw-r--r--indra/newview/llinventorybridge.cpp161
-rw-r--r--indra/newview/llinventorybridge.h1
-rw-r--r--indra/newview/llinventoryfunctions.cpp181
-rw-r--r--indra/newview/llinventoryfunctions.h31
-rw-r--r--indra/newview/llinventorypanel.cpp44
-rw-r--r--indra/newview/lloutfitslist.cpp64
-rw-r--r--indra/newview/lloutfitslist.h8
-rw-r--r--indra/newview/llpaneloutfitedit.cpp82
-rw-r--r--indra/newview/llpaneloutfitedit.h1
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp140
-rw-r--r--indra/newview/llpaneloutfitsinventory.h6
-rw-r--r--indra/newview/llviewerattachmenu.cpp139
-rw-r--r--indra/newview/llviewerattachmenu.h43
-rw-r--r--indra/newview/llviewerinventory.cpp15
-rw-r--r--indra/newview/llwearableitemslist.cpp100
-rw-r--r--indra/newview/llwearableitemslist.h8
-rw-r--r--indra/newview/skins/default/xui/en/floater_about_land.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_attachment.xml8
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_body_part.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_clothing.xml14
-rw-r--r--indra/newview/skins/default/xui/en/menu_cof_gear.xml17
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_gear.xml162
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_tab.xml27
-rw-r--r--indra/newview/skins/default/xui/en/menu_wearable_list_item.xml35
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml22
-rw-r--r--indra/newview/skins/default/xui/en/panel_cof_wearables.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_eyes.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_gloves.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_hair.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_jacket.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_pants.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shirt.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_shoes.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_skin.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_skirt.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_socks.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_underpants.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_edit_undershirt.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_place_profile.xml1
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/pl/floater_about_land.xml4
48 files changed, 1211 insertions, 303 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 9ba44e787b..b00104c427 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -466,6 +466,7 @@ set(viewer_SOURCE_FILES
llviewchildren.cpp
llviewerassetstorage.cpp
llviewerassettype.cpp
+ llviewerattachmenu.cpp
llvieweraudio.cpp
llviewercamera.cpp
llviewerchat.cpp
@@ -984,6 +985,7 @@ set(viewer_HEADER_FILES
llviewchildren.h
llviewerassetstorage.h
llviewerassettype.h
+ llviewerattachmenu.h
llvieweraudio.h
llviewercamera.h
llviewerchat.h
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index e5796f8e63..d2a01aba16 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1974,6 +1974,32 @@ bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool clos
}
// static
+void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id)
+{
+ LLWearable* wearable = LLWearableList::instance().createNewWearable(type);
+ LLAssetType::EType asset_type = wearable->getAssetType();
+ LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE;
+ LLPointer<LLInventoryCallback> cb = wear ? new WearOnAvatarCallback : NULL;
+ LLUUID folder_id;
+
+ if (parent_id.notNull())
+ {
+ folder_id = parent_id;
+ }
+ else
+ {
+ LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type);
+ folder_id = gInventory.findCategoryUUIDForType(folder_type);
+ }
+
+ create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
+ folder_id, wearable->getTransactionID(), wearable->getName(),
+ wearable->getDescription(), asset_type, inv_type, wearable->getType(),
+ wearable->getPermissions().getMaskNextOwner(),
+ cb);
+}
+
+// static
void LLAgentWearables::editWearable(const LLUUID& item_id)
{
LLViewerInventoryItem* item;
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 5d5c5ae371..6d379746ba 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -144,6 +144,7 @@ protected:
//--------------------------------------------------------------------
public:
+ static void createWearable(LLWearableType::EType type, bool wear = false, const LLUUID& parent_id = LLUUID::null);
static void editWearable(const LLUUID& item_id);
bool moveWearable(const LLViewerInventoryItem* item, bool closer_to_body);
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index f27e632180..75ffb9f329 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -704,6 +704,40 @@ void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit)
wearInventoryCategory(cat, false, false);
}
+// Open outfit renaming dialog.
+void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id);
+ if (!cat)
+ {
+ return;
+ }
+
+ LLSD args;
+ args["NAME"] = cat->getName();
+
+ LLSD payload;
+ payload["cat_id"] = outfit_id;
+
+ LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2));
+}
+
+// User typed new outfit name.
+// static
+void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return; // canceled
+
+ std::string outfit_name = response["new_name"].asString();
+ LLStringUtil::trim(outfit_name);
+ if (!outfit_name.empty())
+ {
+ LLUUID cat_id = notification["payload"]["cat_id"].asUUID();
+ rename_category(&gInventory, cat_id, outfit_name);
+ }
+}
+
void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id)
{
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
@@ -714,7 +748,7 @@ void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id)
{
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
- LLFindWearables collector;
+ LLFindWorn collector;
gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector);
@@ -842,6 +876,41 @@ BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
return ((required_wearables & folder_wearables) == required_wearables);
}
+bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id)
+{
+ // Disallow removing the base outfit.
+ if (outfit_cat_id == getBaseOutfitUUID())
+ {
+ return false;
+ }
+
+ // Check if the outfit folder itself is removable.
+ if (!get_is_category_removable(&gInventory, outfit_cat_id))
+ {
+ return false;
+ }
+
+ // Check if the folder contains worn items.
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWorn filter_worn;
+ gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_worn);
+ if (!items.empty())
+ {
+ return false;
+ }
+
+ // Check for the folder's non-removable descendants.
+ LLFindNonRemovableObjects filter_non_removable;
+ LLInventoryModel::item_array_t::const_iterator it;
+ gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable);
+ if (!cats.empty() || !items.empty())
+ {
+ return false;
+ }
+
+ return true;
+}
void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
{
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index dbde055c3a..f1beef5857 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -59,6 +59,7 @@ public:
void wearOutfitByName(const std::string& name);
void changeOutfit(bool proceed, const LLUUID& category, bool append);
void replaceCurrentOutfit(const LLUUID& new_outfit);
+ void renameOutfit(const LLUUID& outfit_id);
void takeOffOutfit(const LLUUID& cat_id);
void addCategoryToCurrentOutfit(const LLUUID& cat_id);
@@ -69,6 +70,9 @@ public:
// Return whether this folder contains minimal contents suitable for making a full outfit.
BOOL getCanMakeFolderIntoOutfit(const LLUUID& folder_id);
+ // Determine whether a given outfit can be removed.
+ bool getCanRemoveOutfit(const LLUUID& outfit_cat_id);
+
// Copy all items in a category.
void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb);
@@ -180,6 +184,8 @@ private:
void purgeCategory(const LLUUID& category, bool keep_outfit_links);
void purgeBaseOutfitLink(const LLUUID& category);
+ static void onOutfitRename(const LLSD& notification, const LLSD& response);
+
std::set<LLUUID> mRegisteredAttachments;
bool mAttachmentInvLinkEnabled;
bool mOutfitIsDirty;
diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp
index 6acd16326a..79ce2f8f6b 100644
--- a/indra/newview/llcofwearables.cpp
+++ b/indra/newview/llcofwearables.cpp
@@ -45,6 +45,7 @@
#include "llwearableitemslist.h"
#include "llpaneloutfitedit.h"
#include "llsidetray.h"
+#include "lltrans.h"
static LLRegisterPanelClassWrapper<LLCOFWearables> t_cof_wearables("cof_wearables");
@@ -52,6 +53,39 @@ const LLSD REARRANGE = LLSD().with("rearrange", LLSD());
static const LLWearableItemNameComparator WEARABLE_NAME_COMPARATOR;
+//////////////////////////////////////////////////////////////////////////
+
+class CofContextMenu : public LLListContextMenu
+{
+protected:
+ static void updateCreateWearableLabel(LLMenuGL* menu, const LLUUID& item_id)
+ {
+ LLMenuItemGL* menu_item = menu->getChild<LLMenuItemGL>("create_new");
+
+ // Hide the "Create new <WEARABLE_TYPE>" if it's irrelevant.
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id);
+ if (!item || !item->isWearableType())
+ {
+ menu_item->setVisible(FALSE);
+ return;
+ }
+
+ // Set proper label for the "Create new <WEARABLE_TYPE>" menu item.
+ LLStringUtil::format_map_t args;
+ LLWearableType::EType w_type = item->getWearableType();
+ args["[WEARABLE_TYPE]"] = LLWearableType::getTypeDefaultNewName(w_type);
+ std::string new_label = LLTrans::getString("CreateNewWearable", args);
+ menu_item->setLabel(new_label);
+ }
+
+ static void createNew(const LLUUID& item_id)
+ {
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id);
+ if (!item || !item->isWearableType()) return;
+
+ LLAgentWearables::createWearable(item->getWearableType(), true);
+ }
+};
//////////////////////////////////////////////////////////////////////////
@@ -72,7 +106,7 @@ protected:
//////////////////////////////////////////////////////////////////////////
-class CofClothingContextMenu : public LLListContextMenu
+class CofClothingContextMenu : public CofContextMenu
{
protected:
@@ -87,10 +121,17 @@ protected:
registrar.add("Clothing.MoveUp", boost::bind(moveWearable, selected_id, false));
registrar.add("Clothing.MoveDown", boost::bind(moveWearable, selected_id, true));
registrar.add("Clothing.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
+ registrar.add("Clothing.Create", boost::bind(createNew, selected_id));
enable_registrar.add("Clothing.OnEnable", boost::bind(&CofClothingContextMenu::onEnable, this, _2));
- return createFromFile("menu_cof_clothing.xml");
+ LLContextMenu* menu = createFromFile("menu_cof_clothing.xml");
+ llassert(menu);
+ if (menu)
+ {
+ updateCreateWearableLabel(menu, selected_id);
+ }
+ return menu;
}
bool onEnable(const LLSD& data)
@@ -106,6 +147,10 @@ protected:
{
return gAgentWearables.canMoveWearable(selected_id, true);
}
+ else if ("take_off" == param)
+ {
+ return get_is_item_worn(selected_id);
+ }
else if ("edit" == param)
{
return gAgentWearables.isWearableModifiable(selected_id);
@@ -120,12 +165,11 @@ protected:
LLViewerInventoryItem* item = gInventory.getItem(item_id);
return LLAppearanceMgr::instance().moveWearable(item, closer_to_body);
}
-
};
//////////////////////////////////////////////////////////////////////////
-class CofBodyPartContextMenu : public LLListContextMenu
+class CofBodyPartContextMenu : public CofContextMenu
{
protected:
@@ -140,10 +184,17 @@ protected:
LLPanelOutfitEdit* panel_oe = dynamic_cast<LLPanelOutfitEdit*>(LLSideTray::getInstance()->getPanel("panel_outfit_edit"));
registrar.add("BodyPart.Replace", boost::bind(&LLPanelOutfitEdit::onReplaceBodyPartMenuItemClicked, panel_oe, selected_id));
registrar.add("BodyPart.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
+ registrar.add("BodyPart.Create", boost::bind(createNew, selected_id));
enable_registrar.add("BodyPart.OnEnable", boost::bind(&CofBodyPartContextMenu::onEnable, this, _2));
- return createFromFile("menu_cof_body_part.xml");
+ LLContextMenu* menu = createFromFile("menu_cof_body_part.xml");
+ llassert(menu);
+ if (menu)
+ {
+ updateCreateWearableLabel(menu, selected_id);
+ }
+ return menu;
}
bool onEnable(const LLSD& data)
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index abdb55ec17..7c5586ec96 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -572,7 +572,7 @@ void LLPanelLandGeneral::refresh()
if (regionp)
{
insert_maturity_into_textbox(mContentRating, gFloaterView->getParentFloater(this), MATURITY);
- mLandType->setText(regionp->getSimProductName());
+ mLandType->setText(LLTrans::getString(regionp->getSimProductName()));
}
// estate owner/manager cannot edit other parts of the parcel
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 1f87b14ddd..b7495f7dbe 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -164,38 +164,7 @@ time_t LLInvFVBridge::getCreationDate() const
// Can be destroyed (or moved to trash)
BOOL LLInvFVBridge::isItemRemovable() const
{
- const LLInventoryModel* model = getInventoryModel();
- if(!model)
- {
- return FALSE;
- }
-
- // Can't delete an item that's in the library.
- if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()))
- {
- return FALSE;
- }
-
- // Disable delete from COF folder; have users explicitly choose "detach/take off",
- // unless the item is not worn but in the COF (i.e. is bugged).
- if (LLAppearanceMgr::instance().getIsProtectedCOFItem(mUUID))
- {
- if (get_is_item_worn(mUUID))
- {
- return FALSE;
- }
- }
-
- const LLInventoryObject *obj = model->getItem(mUUID);
- if (obj && obj->getIsLinkType())
- {
- return TRUE;
- }
- if (get_is_item_worn(mUUID))
- {
- return FALSE;
- }
- return TRUE;
+ return get_is_item_removable(getInventoryModel(), mUUID);
}
// Can be moved to another folder
@@ -833,24 +802,7 @@ void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model,
const LLUUID& new_parent_id,
BOOL restamp)
{
- // Can't move a folder into a child of itself.
- if (model->isObjectDescendentOf(new_parent_id, cat->getUUID()))
- {
- return;
- }
-
- LLInventoryModel::update_list_t update;
- LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
- update.push_back(new_folder);
- model->accountForUpdate(update);
-
- LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
- new_cat->setParent(new_parent_id);
- new_cat->updateParentOnServer(restamp);
- model->updateCategory(new_cat);
- model->notifyObservers();
+ change_category_parent(model, cat, new_parent_id, restamp);
}
LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
@@ -1538,26 +1490,7 @@ public:
// Can be destroyed (or moved to trash)
BOOL LLFolderBridge::isItemRemovable() const
{
- LLInventoryModel* model = getInventoryModel();
- if(!model)
- {
- return FALSE;
- }
-
- if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()))
- {
- return FALSE;
- }
-
- if (!isAgentAvatarValid()) return FALSE;
-
- LLInventoryCategory* category = model->getCategory(mUUID);
- if(!category)
- {
- return FALSE;
- }
-
- if(LLFolderType::lookupIsProtectedType(category->getPreferredType()))
+ if (!get_is_category_removable(getInventoryModel(), mUUID))
{
return FALSE;
}
@@ -1573,6 +1506,7 @@ BOOL LLFolderBridge::isItemRemovable() const
return FALSE;
}
}
+
return TRUE;
}
@@ -2379,21 +2313,8 @@ LLUIImagePtr LLFolderBridge::getOpenIcon() const
BOOL LLFolderBridge::renameItem(const std::string& new_name)
{
- if(!isItemRenameable())
- return FALSE;
- LLInventoryModel* model = getInventoryModel();
- if(!model)
- return FALSE;
- LLViewerInventoryCategory* cat = getCategory();
- if(cat && (cat->getName() != new_name))
- {
- LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
- new_cat->rename(new_name);
- new_cat->updateServer(FALSE);
- model->updateCategory(new_cat);
+ rename_category(getInventoryModel(), mUUID, new_name);
- model->notifyObservers();
- }
// return FALSE because we either notified observers (& therefore
// rebuilt) or we didn't update.
return FALSE;
@@ -2447,36 +2368,7 @@ bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& re
{
// move it to the trash
LLPreview::hide(mUUID);
- LLInventoryModel* model = getInventoryModel();
- if(!model) return FALSE;
-
- const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
-
- // Look for any gestures and deactivate them
- LLInventoryModel::cat_array_t descendent_categories;
- LLInventoryModel::item_array_t descendent_items;
- gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE );
-
- for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin();
- iter != descendent_items.end();
- ++iter)
- {
- const LLViewerInventoryItem* item = (*iter);
- const LLUUID& item_id = item->getUUID();
- if (item->getType() == LLAssetType::AT_GESTURE
- && LLGestureMgr::instance().isGestureActive(item_id))
- {
- LLGestureMgr::instance().deactivateGesture(item_id);
- }
- }
-
- // go ahead and do the normal remove if no 'last calling
- // cards' are being removed.
- LLViewerInventoryCategory* cat = getCategory();
- if(cat)
- {
- LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE);
- }
+ remove_category(getInventoryModel(), mUUID);
return TRUE;
}
return FALSE;
@@ -2672,22 +2564,6 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv
return ((item_array.count() > 0) ? TRUE : FALSE );
}
-class LLFindWorn : public LLInventoryCollectFunctor
-{
-public:
- LLFindWorn() {}
- virtual ~LLFindWorn() {}
- virtual bool operator()(LLInventoryCategory* cat,
- LLInventoryItem* item)
- {
- if (item && get_is_item_worn(item->getUUID()))
- {
- return TRUE;
- }
- return FALSE;
- }
-};
-
BOOL LLFolderBridge::areAnyContentsWorn(LLInventoryModel* model) const
{
LLInventoryModel::cat_array_t cat_array;
@@ -3006,22 +2882,7 @@ void LLFolderBridge::createWearable(LLFolderBridge* bridge, LLWearableType::ETyp
{
if(!bridge) return;
LLUUID parent_id = bridge->getUUID();
- createWearable(parent_id, type);
-}
-
-// Separate function so can be called by global menu as well as right-click
-// menu.
-// static
-void LLFolderBridge::createWearable(const LLUUID &parent_id, LLWearableType::EType type)
-{
- LLWearable* wearable = LLWearableList::instance().createNewWearable(type);
- LLAssetType::EType asset_type = wearable->getAssetType();
- LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE;
- create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
- parent_id, wearable->getTransactionID(), wearable->getName(),
- wearable->getDescription(), asset_type, inv_type, wearable->getType(),
- wearable->getPermissions().getMaskNextOwner(),
- LLPointer<LLInventoryCallback>(NULL));
+ LLAgentWearables::createWearable(type, false, parent_id);
}
void LLFolderBridge::modifyOutfit(BOOL append)
@@ -4898,13 +4759,7 @@ void LLWearableBridge::onEditOnAvatar(void* user_data)
void LLWearableBridge::editOnAvatar()
{
- LLWearable* wearable = gAgentWearables.getWearableFromItemID(mUUID);
- if( wearable )
- {
- LLPanel * panel = LLSideTray::getInstance()->getPanel("sidepanel_appearance");
-
- LLSidepanelAppearance::editWearable(wearable, panel);
- }
+ LLAgentWearables::editWearable(mUUID);
}
// static
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index c5efefac7e..59c1f3d6fb 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -270,7 +270,6 @@ public:
virtual BOOL copyToClipboard() const;
static void createWearable(LLFolderBridge* bridge, LLWearableType::EType type);
- static void createWearable(const LLUUID &parent_folder_id, LLWearableType::EType type);
LLViewerInventoryCategory* getCategory() const;
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 0cc4b0e389..817da34c61 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -130,6 +130,90 @@ void change_item_parent(LLInventoryModel* model,
}
}
+void change_category_parent(LLInventoryModel* model,
+ LLViewerInventoryCategory* cat,
+ const LLUUID& new_parent_id,
+ BOOL restamp)
+{
+ if (!model || !cat)
+ {
+ return;
+ }
+
+ // Can't move a folder into a child of itself.
+ if (model->isObjectDescendentOf(new_parent_id, cat->getUUID()))
+ {
+ return;
+ }
+
+ LLInventoryModel::update_list_t update;
+ LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
+ update.push_back(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
+ update.push_back(new_folder);
+ model->accountForUpdate(update);
+
+ LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
+ new_cat->setParent(new_parent_id);
+ new_cat->updateParentOnServer(restamp);
+ model->updateCategory(new_cat);
+ model->notifyObservers();
+}
+
+void remove_category(LLInventoryModel* model, const LLUUID& cat_id)
+{
+ if (!model || !get_is_category_removable(model, cat_id))
+ {
+ return;
+ }
+
+ // Look for any gestures and deactivate them
+ LLInventoryModel::cat_array_t descendent_categories;
+ LLInventoryModel::item_array_t descendent_items;
+ gInventory.collectDescendents(cat_id, descendent_categories, descendent_items, FALSE);
+
+ for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin();
+ iter != descendent_items.end();
+ ++iter)
+ {
+ const LLViewerInventoryItem* item = (*iter);
+ const LLUUID& item_id = item->getUUID();
+ if (item->getType() == LLAssetType::AT_GESTURE
+ && LLGestureMgr::instance().isGestureActive(item_id))
+ {
+ LLGestureMgr::instance().deactivateGesture(item_id);
+ }
+ }
+
+ // go ahead and do the normal remove if no 'last calling
+ // cards' are being removed.
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ change_category_parent(model, cat, trash_id, TRUE);
+ }
+}
+
+void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name)
+{
+ LLViewerInventoryCategory* cat;
+
+ if (!model ||
+ !get_is_category_renameable(model, cat_id) ||
+ (cat = model->getCategory(cat_id)) == NULL ||
+ cat->getName() == new_name)
+ {
+ return;
+ }
+
+ LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
+ new_cat->rename(new_name);
+ new_cat->updateServer(FALSE);
+ model->updateCategory(new_cat);
+
+ model->notifyObservers();
+}
BOOL get_is_item_worn(const LLUUID& id)
{
@@ -160,6 +244,83 @@ BOOL get_is_item_worn(const LLUUID& id)
return FALSE;
}
+BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id)
+{
+ if (!model)
+ {
+ return FALSE;
+ }
+
+ // Can't delete an item that's in the library.
+ if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID()))
+ {
+ return FALSE;
+ }
+
+ // Disable delete from COF folder; have users explicitly choose "detach/take off",
+ // unless the item is not worn but in the COF (i.e. is bugged).
+ if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id))
+ {
+ if (get_is_item_worn(id))
+ {
+ return FALSE;
+ }
+ }
+
+ const LLInventoryObject *obj = model->getItem(id);
+ if (obj && obj->getIsLinkType())
+ {
+ return TRUE;
+ }
+ if (get_is_item_worn(id))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id)
+{
+ // This function doesn't check the folder's children.
+
+ if (!model)
+ {
+ return FALSE;
+ }
+
+ if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID()))
+ {
+ return FALSE;
+ }
+
+ if (!isAgentAvatarValid()) return FALSE;
+
+ LLInventoryCategory* category = model->getCategory(id);
+ if (!category)
+ {
+ return FALSE;
+ }
+
+ if (LLFolderType::lookupIsProtectedType(category->getPreferredType()))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id)
+{
+ LLViewerInventoryCategory* cat = model->getCategory(id);
+
+ if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) &&
+ cat->getOwnerID() == gAgent.getID())
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
void show_item_profile(const LLUUID& item_uuid)
{
LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid);
@@ -376,6 +537,26 @@ void LLFindWearablesOfType::setType(LLWearableType::EType type)
mWearableType = type;
}
+bool LLFindWorn::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ return item && get_is_item_worn(item->getUUID());
+}
+
+bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ if (item)
+ {
+ return !get_is_item_removable(&gInventory, item->getUUID());
+ }
+ if (cat)
+ {
+ return !get_is_category_removable(&gInventory, cat->getUUID());
+ }
+
+ llwarns << "Not a category and not an item?" << llendl;
+ return false;
+}
+
///----------------------------------------------------------------------------
/// LLAssetIDMatches
///----------------------------------------------------------------------------
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index bb365573d7..33b52cfd5e 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -46,6 +46,12 @@
// Is this item or its baseitem is worn, attached, etc...
BOOL get_is_item_worn(const LLUUID& id);
+BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id);
+
+BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id);
+
+BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id);
+
void show_item_profile(const LLUUID& item_uuid);
void show_item_original(const LLUUID& item_uuid);
@@ -55,6 +61,15 @@ void change_item_parent(LLInventoryModel* model,
const LLUUID& new_parent_id,
BOOL restamp);
+void change_category_parent(LLInventoryModel* model,
+ LLViewerInventoryCategory* cat,
+ const LLUUID& new_parent_id,
+ BOOL restamp);
+
+void remove_category(LLInventoryModel* model, const LLUUID& cat_id);
+
+void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name);
+
// Generates a string containing the path to the item specified by item_id.
void append_path(const LLUUID& id, std::string& path);
@@ -309,6 +324,22 @@ private:
LLWearableType::EType mWearableType;
};
+// Find worn items.
+class LLFindWorn : public LLInventoryCollectFunctor
+{
+public:
+ LLFindWorn() {}
+ virtual ~LLFindWorn() {}
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+};
+
+// Collect non-removable folders and items.
+class LLFindNonRemovableObjects : public LLInventoryCollectFunctor
+{
+public:
+ virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
+};
+
/** Inventory Collector Functions
** **
*******************************************************************************/
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 4766c1c227..bb3f34dde2 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -49,6 +49,7 @@
#include "llsidepanelinventory.h"
#include "llsidetray.h"
#include "llscrollcontainer.h"
+#include "llviewerattachmenu.h"
#include "llviewerfoldertype.h"
#include "llvoavatarself.h"
@@ -877,48 +878,19 @@ bool LLInventoryPanel::beginIMSession()
bool LLInventoryPanel::attachObject(const LLSD& userdata)
{
+ // Copy selected item UUIDs to a vector.
std::set<LLUUID> selected_items = mFolderRoot->getSelectionList();
-
- std::string joint_name = userdata.asString();
- LLViewerJointAttachment* attachmentp = NULL;
- 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;
- if (attachment->getName() == joint_name)
- {
- attachmentp = attachment;
- break;
- }
- }
- if (attachmentp == NULL)
- {
- return true;
- }
-
+ uuid_vec_t items;
for (std::set<LLUUID>::const_iterator set_iter = selected_items.begin();
set_iter != selected_items.end();
++set_iter)
{
- const LLUUID &id = *set_iter;
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id);
- if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()))
- {
- rez_attachment(item, attachmentp);
- }
- else if(item && item->isFinished())
- {
- // must be in library. copy it to our inventory and put it on.
- LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp);
- copy_inventory_item(gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- LLUUID::null,
- std::string(),
- cb);
- }
+ items.push_back(*set_iter);
}
+
+ // Attach selected items.
+ LLViewerAttachMenu::attachObjects(items, userdata.asString());
+
gFocusMgr.setKeyboardFocus(NULL);
return true;
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 7bf41b0f92..77db280487 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -43,6 +43,8 @@
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "lllistcontextmenu.h"
+#include "llnotificationsutil.h"
+#include "llsidetray.h"
#include "lltransutil.h"
#include "llviewermenu.h"
#include "llvoavatar.h"
@@ -68,12 +70,63 @@ protected:
boost::bind(&LLAppearanceMgr::addCategoryToCurrentOutfit, &LLAppearanceMgr::instance(), selected_id));
registrar.add("Outfit.TakeOff",
boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
- // *TODO: implement this
- // registrar.add("Outfit.Rename", boost::bind());
- // registrar.add("Outfit.Delete", boost::bind());
+ registrar.add("Outfit.Edit", boost::bind(editOutfit));
+ registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
+ registrar.add("Outfit.Delete", boost::bind(deleteOutfit, selected_id));
+
+ enable_registrar.add("Outfit.OnEnable", boost::bind(&OutfitContextMenu::onEnable, this, _2));
return createFromFile("menu_outfit_tab.xml");
}
+
+ bool onEnable(const LLSD& data)
+ {
+ std::string param = data.asString();
+ LLUUID outfit_cat_id = mUUIDs.back();
+ bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == outfit_cat_id;
+
+ if ("wear_replace" == param)
+ {
+ return !is_worn;
+ }
+ else if ("wear_add" == param)
+ {
+ return !is_worn;
+ }
+ else if ("take_off" == param)
+ {
+ return is_worn;
+ }
+ else if ("edit" == param)
+ {
+ return is_worn;
+ }
+ else if ("rename" == param)
+ {
+ return get_is_category_renameable(&gInventory, outfit_cat_id);
+ }
+ else if ("delete" == param)
+ {
+ return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id);
+ }
+
+ return true;
+ }
+
+ static void editOutfit()
+ {
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
+ }
+
+ static void renameOutfit(const LLUUID& outfit_cat_id)
+ {
+ LLAppearanceMgr::instance().renameOutfit(outfit_cat_id);
+ }
+
+ static void deleteOutfit(const LLUUID& outfit_cat_id)
+ {
+ remove_category(&gInventory, outfit_cat_id);
+ }
};
//////////////////////////////////////////////////////////////////////////
@@ -304,6 +357,10 @@ void LLOutfitsList::performAction(std::string action)
{
LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, TRUE );
}
+ else if ("rename_outfit" == action)
+ {
+ LLAppearanceMgr::instance().renameOutfit(mSelectedOutfitUUID);
+ }
}
void LLOutfitsList::setFilterSubString(const std::string& string)
@@ -578,4 +635,5 @@ bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y)
S32 header_bottom = tab->getLocalRect().getHeight() - tab->getHeaderHeight();
return y >= header_bottom;
}
+
// EOF
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index 6dbdf00067..44f6ec908b 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -64,12 +64,12 @@ public:
void refreshList(const LLUUID& category_id);
- void onSelectionChange(LLUICtrl* ctrl);
-
void performAction(std::string action);
void setFilterSubString(const std::string& string);
+ const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; }
+
private:
/**
* Reads xml with accordion tab and Flat list from xml file.
@@ -108,6 +108,10 @@ private:
void onAccordionTabDoubleClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
+ void onSelectionChange(LLUICtrl* ctrl);
+
+ static void onOutfitRename(const LLSD& notification, const LLSD& response);
+
LLInventoryCategoriesObserver* mCategoriesObserver;
LLAccordionCtrl* mAccordion;
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 0ca5938c97..dee9572357 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -79,6 +79,70 @@ const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
static const std::string REVERT_BTN("revert_btn");
+class LLPanelOutfitEditGearMenu
+{
+public:
+ static LLMenuGL* create()
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+
+ registrar.add("Wearable.Create", boost::bind(onCreate, _2));
+
+ LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ "menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+ llassert(menu);
+ if (menu)
+ {
+ populateCreateWearableSubmenus(menu);
+ menu->buildDrawLabels();
+ }
+
+ return menu;
+ }
+
+private:
+ static void onCreate(const LLSD& param)
+ {
+ LLWearableType::EType type = LLWearableType::typeNameToType(param.asString());
+ if (type == LLWearableType::WT_NONE)
+ {
+ llwarns << "Invalid wearable type" << llendl;
+ return;
+ }
+
+ LLAgentWearables::createWearable(type, true);
+ }
+
+ // Populate the menu with items like "New Skin", "New Pants", etc.
+ static void populateCreateWearableSubmenus(LLMenuGL* menu)
+ {
+ LLView* menu_clothes = gMenuHolder->findChildView("COF.Gear.New_Clothes", FALSE);
+ LLView* menu_bp = gMenuHolder->findChildView("COF.Geear.New_Body_Parts", FALSE);
+
+ if (!menu_clothes || !menu_bp)
+ {
+ llassert(menu_clothes && menu_bp);
+ return;
+ }
+
+ for (U8 i = LLWearableType::WT_SHAPE; i != (U8) LLWearableType::WT_COUNT; ++i)
+ {
+ LLWearableType::EType type = (LLWearableType::EType) i;
+ const std::string& type_name = LLWearableType::getTypeName(type);
+
+ LLMenuItemCallGL::Params p;
+ p.name = type_name;
+ p.label = LLWearableType::getTypeDefaultNewName(type);
+ p.on_click.function_name = "Wearable.Create";
+ p.on_click.parameter = LLSD(type_name);
+
+ LLView* parent = LLWearableType::getAssetType(type) == LLAssetType::AT_CLOTHING ?
+ menu_clothes : menu_bp;
+ LLUICtrlFactory::create<LLMenuItemCallGL>(p, parent);
+ }
+ }
+};
+
class LLCOFObserver : public LLInventoryObserver
{
public:
@@ -721,29 +785,13 @@ void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button)
{
if(!mGearMenu)
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
-
- registrar.add("Gear.OnClick", boost::bind(&LLPanelOutfitEdit::onGearMenuItemClick, this, _2));
-
- mGearMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
- "menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
- mGearMenu->buildDrawLabels();
- mGearMenu->updateParent(LLMenuGL::sMenuContainer);
+ mGearMenu = LLPanelOutfitEditGearMenu::create();
}
S32 menu_y = mGearMenu->getRect().getHeight() + clicked_button->getRect().getHeight();
LLMenuGL::showPopup(clicked_button, mGearMenu, 0, menu_y);
}
-void LLPanelOutfitEdit::onGearMenuItemClick(const LLSD& data)
-{
- std::string param = data.asString();
- if("add" == param)
- {
- // TODO
- }
-}
-
void LLPanelOutfitEdit::showFilteredWearableItemsList(LLWearableType::EType type)
{
mWearableListTypeCollector->setType(type);
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 6ce581f5f7..802386c573 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -132,7 +132,6 @@ public:
private:
void onGearButtonClick(LLUICtrl* clicked_button);
- void onGearMenuItemClick(const LLSD& data);
void showFilteredWearableItemsList(LLWearableType::EType type);
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index 9babddc033..5f67f3d989 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -42,6 +42,7 @@
#include "llfloaterworldmap.h"
#include "llfloaterinventory.h"
#include "llfoldervieweventlistener.h"
+#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h"
@@ -70,11 +71,134 @@ static const std::string COF_TAB_NAME = "cof_tab";
static LLRegisterPanelClassWrapper<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory");
+class LLOutfitListGearMenu
+{
+public:
+ LLOutfitListGearMenu(LLOutfitsList* olist)
+ : mOutfitList(olist),
+ mMenu(NULL)
+ {
+ llassert_always(mOutfitList);
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+ registrar.add("Gear.Wear", boost::bind(&LLOutfitListGearMenu::onWear, this));
+ registrar.add("Gear.TakeOff", boost::bind(&LLOutfitListGearMenu::onTakeOff, this));
+ registrar.add("Gear.Rename", boost::bind(&LLOutfitListGearMenu::onRename, this));
+ registrar.add("Gear.Delete", boost::bind(&LLOutfitListGearMenu::onDelete, this));
+ registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenu::onCreate, this, _2));
+
+ enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenu::onEnable, this, _2));
+
+ mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ "menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ llassert(mMenu);
+ }
+
+ LLMenuGL* getMenu() { return mMenu; }
+
+private:
+ const LLUUID& getSelectedOutfitID()
+ {
+ return mOutfitList->getSelectedOutfitUUID();
+ }
+
+ LLViewerInventoryCategory* getSelectedOutfit()
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.isNull())
+ {
+ return NULL;
+ }
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id);
+ return cat;
+ }
+
+ void onWear()
+ {
+ LLViewerInventoryCategory* selected_outfit = getSelectedOutfit();
+ if (selected_outfit)
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory(
+ selected_outfit, /*copy=*/ FALSE, /*append=*/ FALSE);
+ }
+ }
+
+ void onTakeOff()
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.notNull())
+ {
+ LLAppearanceMgr::instance().takeOffOutfit(selected_outfit_id);
+ }
+ }
+
+ void onRename()
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.notNull())
+ {
+ LLAppearanceMgr::instance().renameOutfit(selected_outfit_id);
+ }
+ }
+
+ void onDelete()
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.notNull())
+ {
+ remove_category(&gInventory, selected_outfit_id);
+ }
+ }
+
+ void onCreate(const LLSD& data)
+ {
+ LLWearableType::EType type = LLWearableType::typeNameToType(data.asString());
+ if (type == LLWearableType::WT_NONE)
+ {
+ llwarns << "Invalid wearable type" << llendl;
+ return;
+ }
+
+ LLAgentWearables::createWearable(type, true);
+ }
+
+ bool onEnable(LLSD::String param)
+ {
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id;
+
+ if ("wear" == param)
+ {
+ return !is_worn;
+ }
+ else if ("take_off" == param)
+ {
+ return is_worn;
+ }
+ else if ("rename" == param)
+ {
+ return get_is_category_renameable(&gInventory, selected_outfit_id);
+ }
+ else if ("delete" == param)
+ {
+ return LLAppearanceMgr::instance().getCanRemoveOutfit(selected_outfit_id);
+ }
+
+ return true;
+ }
+
+ LLOutfitsList* mOutfitList;
+ LLMenuGL* mMenu;
+};
LLPanelOutfitsInventory::LLPanelOutfitsInventory() :
mMyOutfitsPanel(NULL),
mCurrentOutfitPanel(NULL),
mParent(NULL),
+ mGearMenu(NULL),
mInitialized(false)
{
mSavedFolderState = new LLSaveFolderState();
@@ -84,6 +208,7 @@ LLPanelOutfitsInventory::LLPanelOutfitsInventory() :
LLPanelOutfitsInventory::~LLPanelOutfitsInventory()
{
+ delete mGearMenu;
delete mSavedFolderState;
}
@@ -374,7 +499,7 @@ void LLPanelOutfitsInventory::initListCommandsHandlers()
{
mListCommands = getChild<LLPanel>("bottom_panel");
- mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelOutfitsInventory::onGearButtonClick, this));
+ mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelOutfitsInventory::showGearMenu, this));
mListCommands->childSetAction("trash_btn", boost::bind(&LLPanelOutfitsInventory::onTrashButtonClick, this));
mListCommands->childSetAction("wear_btn", boost::bind(&LLPanelOutfitsInventory::onWearButtonClick, this));
@@ -385,8 +510,7 @@ void LLPanelOutfitsInventory::initListCommandsHandlers()
, _7 // EAcceptance* accept
));
- mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_outfit_gear.xml",
- gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ mGearMenu = new LLOutfitListGearMenu(mMyOutfitsPanel);
}
void LLPanelOutfitsInventory::updateListCommands()
@@ -401,18 +525,14 @@ void LLPanelOutfitsInventory::updateListCommands()
mSaveComboBtn->setSaveBtnEnabled(make_outfit_enabled);
}
-void LLPanelOutfitsInventory::onGearButtonClick()
-{
- showActionMenu(mMenuGearDefault,"options_gear_btn");
-}
-
-void LLPanelOutfitsInventory::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
+void LLPanelOutfitsInventory::showGearMenu()
{
+ LLMenuGL* menu = mGearMenu ? mGearMenu->getMenu() : NULL;
if (menu)
{
menu->buildDrawLabels();
menu->updateParent(LLMenuGL::sMenuContainer);
- LLView* spawning_view = getChild<LLView> (spawning_view_name);
+ LLView* spawning_view = getChild<LLView>("options_gear_btn");
S32 menu_x, menu_y;
//show menu in co-ordinates of panel
spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this);
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index 7bdd37c16c..aff7839bcc 100644
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -47,6 +47,7 @@ class LLMenuGL;
class LLSidepanelAppearance;
class LLTabContainer;
class LLSaveOutfitComboBtn;
+class LLOutfitListGearMenu;
class LLPanelOutfitsInventory : public LLPanel
{
@@ -116,9 +117,8 @@ private:
protected:
void initListCommandsHandlers();
void updateListCommands();
- void onGearButtonClick();
void onWearButtonClick();
- void showActionMenu(LLMenuGL* menu, std::string spawning_view_name);
+ void showGearMenu();
void onTrashButtonClick();
void onClipboardAction(const LLSD& userdata);
BOOL isActionEnabled(const LLSD& command_name);
@@ -129,7 +129,7 @@ protected:
void onWearablesLoaded();
private:
LLPanel* mListCommands;
- LLMenuGL* mMenuGearDefault;
+ LLOutfitListGearMenu* mGearMenu;
LLMenuGL* mMenuAdd;
// List Commands //
////////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llviewerattachmenu.cpp b/indra/newview/llviewerattachmenu.cpp
new file mode 100644
index 0000000000..f7f5ec72fd
--- /dev/null
+++ b/indra/newview/llviewerattachmenu.cpp
@@ -0,0 +1,139 @@
+/**
+ * @file llviewerattachmenu.cpp
+ * @brief "Attach to" / "Attach to HUD" submenus.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerattachmenu.h"
+
+// project includes
+#include "llagent.h"
+#include "llinventorybridge.h" // for rez_attachment()
+#include "llinventorymodel.h"
+#include "llviewerinventory.h"
+#include "llviewermenu.h" // for gMenuHolder
+#include "llvoavatarself.h"
+
+// linden libraries
+#include "llmenugl.h"
+#include "lltrans.h"
+
+// static
+void LLViewerAttachMenu::populateMenus(const std::string& attach_to_menu_name, const std::string& attach_to_hud_menu_name)
+{
+ // *TODO: share this code with other similar menus
+ // (inventory panel context menu, in-world object menu).
+
+ if (attach_to_menu_name.empty() || attach_to_hud_menu_name.empty() || !isAgentAvatarValid()) return;
+
+ LLContextMenu* attach_menu = gMenuHolder->getChild<LLContextMenu>(attach_to_menu_name);
+ LLContextMenu* attach_hud_menu = gMenuHolder->getChild<LLContextMenu>(attach_to_hud_menu_name);
+
+ if (!attach_menu || attach_menu->getChildCount() != 0 ||
+ !attach_hud_menu || attach_hud_menu->getChildCount() != 0)
+ {
+ return;
+ }
+
+ // Populate "Attach to..." / "Attach to HUD..." submenus.
+ 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;
+ LLMenuItemCallGL::Params p;
+ std::string submenu_name = attachment->getName();
+ std::string translated_submenu_name;
+
+ if (LLTrans::findString(translated_submenu_name, submenu_name))
+ {
+ p.name = (" ") + translated_submenu_name + " ";
+ }
+ else
+ {
+ p.name = submenu_name;
+ }
+
+ LLSD cbparams;
+ cbparams["index"] = curiter->first;
+ cbparams["label"] = attachment->getName();
+ p.on_click.function_name = "Object.Attach";
+ p.on_click.parameter = LLSD(attachment->getName());
+ p.on_enable.function_name = "Attachment.Label";
+ p.on_enable.parameter = cbparams;
+
+ LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(p);
+ LLView* parent_menu = attachment->getIsHUDAttachment() ? attach_hud_menu : attach_menu;
+ parent_menu->addChild(item);
+ }
+}
+
+// static
+void LLViewerAttachMenu::attachObjects(const uuid_vec_t& items, const std::string& joint_name)
+{
+ LLViewerJointAttachment* attachmentp = NULL;
+ 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;
+ if (attachment->getName() == joint_name)
+ {
+ attachmentp = attachment;
+ break;
+ }
+ }
+ if (attachmentp == NULL)
+ {
+ return;
+ }
+
+ for (uuid_vec_t::const_iterator it = items.begin(); it != items.end(); ++it)
+ {
+ const LLUUID &id = *it;
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getLinkedItem(id);
+ if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()))
+ {
+ rez_attachment(item, attachmentp);
+ }
+ else if(item && item->isFinished())
+ {
+ // must be in library. copy it to our inventory and put it on.
+ LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp);
+ copy_inventory_item(gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ LLUUID::null,
+ std::string(),
+ cb);
+ }
+ }
+}
diff --git a/indra/newview/llviewerattachmenu.h b/indra/newview/llviewerattachmenu.h
new file mode 100644
index 0000000000..d1db9914f3
--- /dev/null
+++ b/indra/newview/llviewerattachmenu.h
@@ -0,0 +1,43 @@
+/**
+ * @file llviewerattachmenu.h
+ * @brief "Attach to" / "Attach to HUD" submenus.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ *
+ * Copyright (c) 2010, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVIEWERATTACHMENU_H
+#define LL_LLVIEWERATTACHMENU_H
+
+class LLViewerAttachMenu
+{
+public:
+ static void populateMenus(const std::string& attach_to_menu_name, const std::string& attach_to_hud_menu_name);
+ static void attachObjects(const uuid_vec_t& items, const std::string& joint_name);
+};
+
+#endif // LL_LLVIEWERATTACHMENU_H
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 4cb5e86fc2..d745356dcd 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -39,6 +39,7 @@
#include "llagent.h"
#include "llagentcamera.h"
+#include "llagentwearables.h"
#include "llviewerfoldertype.h"
#include "llfolderview.h"
#include "llviewercontrol.h"
@@ -881,6 +882,14 @@ void WearOnAvatarCallback::fire(const LLUUID& inv_item)
void ModifiedCOFCallback::fire(const LLUUID& inv_item)
{
LLAppearanceMgr::instance().updateAppearanceFromCOF();
+
+ if (LLSideTray::getInstance()->isPanelActive("sidepanel_appearance"))
+ {
+ // *HACK: Edit the wearable that has just been worn
+ // only if the Appearance SP is currently opened.
+ LLAgentWearables::editWearable(inv_item);
+ }
+
// TODO: camera mode may not be changed if a debug setting is tweaked
if( gAgentCamera.cameraCustomizeAvatar() )
{
@@ -1241,10 +1250,8 @@ void menu_create_inventory_item(LLFolderView* root, LLFolderBridge *bridge, cons
LLWearableType::EType wearable_type = LLWearableType::typeNameToType(type_name);
if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT)
{
- LLAssetType::EType asset_type = LLWearableType::getAssetType(wearable_type);
- LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type);
- const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(folder_type);
- LLFolderBridge::createWearable(parent_id, wearable_type);
+ const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null;
+ LLAgentWearables::createWearable(wearable_type, false, parent_id);
}
else
{
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index cfb48a22bb..c35b45d446 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -41,6 +41,7 @@
#include "llinventorymodel.h"
#include "llmenugl.h" // for LLContextMenu
#include "lltransutil.h"
+#include "llviewerattachmenu.h"
class LLFindOutfitItems : public LLInventoryCollectFunctor
{
@@ -511,7 +512,9 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu()
// Register handlers common for all wearable types.
registrar.add("Wearable.Wear", boost::bind(handleMultiple, wear, ids));
registrar.add("Wearable.Edit", boost::bind(handleMultiple, LLAgentWearables::editWearable, ids));
+ registrar.add("Wearable.CreateNew", boost::bind(createNewWearable, selected_id));
registrar.add("Wearable.ShowOriginal", boost::bind(show_item_original, selected_id));
+ registrar.add("Wearable.TakeOffDetach", boost::bind(handleMultiple, take_off, ids));
// Register handlers for clothing.
registrar.add("Clothing.TakeOff", boost::bind(handleMultiple, take_off, ids));
@@ -521,12 +524,16 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu()
// Register handlers for attachments.
registrar.add("Attachment.Detach", boost::bind(handleMultiple, take_off, ids));
registrar.add("Attachment.Profile", boost::bind(show_item_profile, selected_id));
+ registrar.add("Object.Attach", boost::bind(LLViewerAttachMenu::attachObjects, ids, _2));
// Create the menu.
LLContextMenu* menu = createFromFile("menu_wearable_list_item.xml");
// Determine which items should be visible/enabled.
updateItemsVisibility(menu);
+
+ // Update labels for the items requiring that.
+ updateItemsLabels(menu);
return menu;
}
@@ -540,10 +547,10 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
const uuid_vec_t& ids = mUUIDs; // selected items IDs
U32 mask = 0; // mask of selected items' types
- U32 nitems = ids.size(); // number of selected items
- U32 nworn = 0; // number of worn items among the selected ones
- U32 nwornlinks = 0; // number of worn links among the selected items
- U32 neditable = 0; // number of editable items among the selected ones
+ U32 n_items = ids.size(); // number of selected items
+ U32 n_worn = 0; // number of worn items among the selected ones
+ U32 n_links = 0; // number of links among the selected items
+ U32 n_editable = 0; // number of editable items among the selected ones
for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
{
@@ -565,38 +572,82 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
if (is_worn)
{
- ++nworn;
-
- if (is_link)
- {
- ++nwornlinks;
- }
+ ++n_worn;
}
if (is_editable)
{
- ++neditable;
+ ++n_editable;
+ }
+ if (is_link)
+ {
+ ++n_links;
}
} // for
// *TODO: eliminate multiple traversals over the menu items
- // *TODO: try disabling items rather than hiding them
- // *FIX: we may hide *all* items and thus get an ugly empty menu
- setMenuItemVisible(menu, "wear", nworn == 0);
- setMenuItemVisible(menu, "edit", mask & (MASK_CLOTHING|MASK_BODYPART) && nitems == 1 && neditable == 1);
- setMenuItemVisible(menu, "show_original", nitems == 1 && nwornlinks == nitems);
- setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && nworn == nitems); // selected only worn clothes
- setMenuItemVisible(menu, "detach", mask == MASK_ATTACHMENT && nworn == nitems);
- setMenuItemVisible(menu, "object_profile", mask == MASK_ATTACHMENT && nitems == 1);
+ setMenuItemVisible(menu, "wear", n_worn == 0);
+ setMenuItemVisible(menu, "edit", mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1);
+ setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1);
+ setMenuItemVisible(menu, "create_new", mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1);
+ setMenuItemEnabled(menu, "show_original", n_items == 1 && n_links == n_items);
+ setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items);
+ setMenuItemVisible(menu, "detach", mask == MASK_ATTACHMENT && n_worn == n_items);
+ setMenuItemVisible(menu, "take_off_or_detach", mask == (MASK_ATTACHMENT|MASK_CLOTHING));
+ setMenuItemEnabled(menu, "take_off_or_detach", n_worn == n_items);
+ setMenuItemVisible(menu, "object_profile", mask & (MASK_ATTACHMENT|MASK_CLOTHING));
+ setMenuItemEnabled(menu, "object_profile", n_items == 1);
+
+ // Populate or hide the "Attach to..." / "Attach to HUD..." submenus.
+ if (mask == MASK_ATTACHMENT && n_worn == 0)
+ {
+ LLViewerAttachMenu::populateMenus("wearable_attach_to", "wearable_attach_to_hud");
+ }
+ else
+ {
+ setMenuItemVisible(menu, "wearable_attach_to", false);
+ setMenuItemVisible(menu, "wearable_attach_to_hud", false);
+ }
+
+ if (mask & MASK_UNKNOWN)
+ {
+ llwarns << "Non-wearable items passed." << llendl;
+ }
+}
+
+void LLWearableItemsList::ContextMenu::updateItemsLabels(LLContextMenu* menu)
+{
+ llassert(menu);
+ if (!menu) return;
+
+ // Set proper label for the "Create new <WEARABLE_TYPE>" menu item.
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(mUUIDs.back());
+ if (!item || !item->isWearableType()) return;
+
+ LLStringUtil::format_map_t args;
+ LLWearableType::EType w_type = item->getWearableType();
+ args["[WEARABLE_TYPE]"] = LLWearableType::getTypeDefaultNewName(w_type);
+ std::string new_label = LLTrans::getString("CreateNewWearable", args);
+
+ LLMenuItemGL* menu_item = menu->getChild<LLMenuItemGL>("create_new");
+ menu_item->setLabel(new_label);
}
// We need this method to convert non-zero BOOL values to exactly 1 (TRUE).
// Otherwise code relying on a BOOL value being TRUE may fail
// (I experienced a weird assert in LLView::drawChildren() because of that.
+// static
void LLWearableItemsList::ContextMenu::setMenuItemVisible(LLContextMenu* menu, const std::string& name, bool val)
{
menu->setItemVisible(name, val);
}
+// static
+void LLWearableItemsList::ContextMenu::setMenuItemEnabled(LLContextMenu* menu, const std::string& name, bool val)
+{
+ menu->setItemEnabled(name, val);
+}
+
+// static
void LLWearableItemsList::ContextMenu::updateMask(U32& mask, LLAssetType::EType at)
{
if (at == LLAssetType::AT_CLOTHING)
@@ -613,8 +664,17 @@ void LLWearableItemsList::ContextMenu::updateMask(U32& mask, LLAssetType::EType
}
else
{
- llwarns << "Unsupported asset type: " << at << llendl;
+ mask |= MASK_UNKNOWN;
}
}
+// static
+void LLWearableItemsList::ContextMenu::createNewWearable(const LLUUID& item_id)
+{
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id);
+ if (!item || !item->isWearableType()) return;
+
+ LLAgentWearables::createWearable(item->getWearableType(), true);
+}
+
// EOF
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
index 995a8976f3..0ed480a92a 100644
--- a/indra/newview/llwearableitemslist.h
+++ b/indra/newview/llwearableitemslist.h
@@ -315,12 +315,16 @@ public:
MASK_CLOTHING = 0x01,
MASK_BODYPART = 0x02,
MASK_ATTACHMENT = 0x04,
+ MASK_UNKNOWN = 0x08,
};
/* virtual */ LLContextMenu* createMenu();
void updateItemsVisibility(LLContextMenu* menu);
- void setMenuItemVisible(LLContextMenu* menu, const std::string& name, bool val);
- void updateMask(U32& mask, LLAssetType::EType at);
+ void updateItemsLabels(LLContextMenu* menu);
+ static void setMenuItemVisible(LLContextMenu* menu, const std::string& name, bool val);
+ 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);
};
struct Params : public LLInitParam::Block<Params, LLInventoryItemsList::Params>
diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml
index 5f28fa6495..54ef6d65a7 100644
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -756,7 +756,7 @@ Leyla Linden </text>
mouse_opaque="false"
name="resellable_clause"
word_wrap="true"
- width="330">
+ width="360">
Land in this region may not be resold.
</text>
<text
diff --git a/indra/newview/skins/default/xui/en/menu_cof_attachment.xml b/indra/newview/skins/default/xui/en/menu_cof_attachment.xml
index b422d87938..c402100fb1 100644
--- a/indra/newview/skins/default/xui/en/menu_cof_attachment.xml
+++ b/indra/newview/skins/default/xui/en/menu_cof_attachment.xml
@@ -10,12 +10,4 @@
function="Attachment.Detach"
parameter="detach"/>
</menu_item_call>
- <context_menu
- label="Attach to"
- layout="topleft"
- name="attach_to" />
- <context_menu
- label="Attach to HUD"
- layout="topleft"
- name="attach_to_hud" />
</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_body_part.xml b/indra/newview/skins/default/xui/en/menu_cof_body_part.xml
index 01008ef203..f0e8461360 100644
--- a/indra/newview/skins/default/xui/en/menu_cof_body_part.xml
+++ b/indra/newview/skins/default/xui/en/menu_cof_body_part.xml
@@ -19,4 +19,15 @@
function="BodyPart.OnEnable"
parameter="edit" />
</menu_item_call>
+ <menu_item_call
+ label="Create New"
+ layout="topleft"
+ name="create_new"
+ translate="false">
+ <on_click
+ function="BodyPart.Create"/>
+ <on_enable
+ function="BodyPart.OnEnable"
+ parameter="create" />
+ </menu_item_call>
</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_clothing.xml b/indra/newview/skins/default/xui/en/menu_cof_clothing.xml
index f9cb29f0d7..12ee9b045b 100644
--- a/indra/newview/skins/default/xui/en/menu_cof_clothing.xml
+++ b/indra/newview/skins/default/xui/en/menu_cof_clothing.xml
@@ -8,6 +8,9 @@
name="take_off">
<on_click
function="Clothing.TakeOff" />
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="take_off" />
</menu_item_call>
<menu_item_call
label="Move Up a Layer"
@@ -39,4 +42,15 @@
function="Clothing.OnEnable"
parameter="edit" />
</menu_item_call>
+ <menu_item_call
+ label="Create New"
+ layout="topleft"
+ name="create_new"
+ translate="false">
+ <on_click
+ function="Clothing.Create"/>
+ <on_enable
+ function="Clothing.OnEnable"
+ parameter="create" />
+ </menu_item_call>
</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_gear.xml b/indra/newview/skins/default/xui/en/menu_cof_gear.xml
index 982d4f2015..c2a11a64ec 100644
--- a/indra/newview/skins/default/xui/en/menu_cof_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_cof_gear.xml
@@ -2,15 +2,12 @@
<menu
layout="topleft"
name="Gear COF">
- <menu_item_call
- label="Add To Outfit"
+ <menu
+ label="New Clothes"
layout="topleft"
- name="add">
- <on_click
- function="Gear.OnClick"
- parameter="add"/>
- <on_enable
- function="Gear.OnEnable"
- parameter="add" />
- </menu_item_call>
+ name="COF.Gear.New_Clothes" />
+ <menu
+ label="New Body Parts"
+ layout="topleft"
+ name="COF.Geear.New_Body_Parts" />
</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
index dfc72b557c..b5eda8e999 100644
--- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
@@ -7,31 +7,174 @@
layout="topleft"
name="wear">
<on_click
- function="Gear.OnClick"
- parameter="wear"/>
+ function="Gear.Wear" />
<on_enable
function="Gear.OnEnable"
parameter="wear" />
</menu_item_call>
<menu_item_call
- label="Take Off - Remove Current Outfit"
+ label="Take Off - Remove from Current Outfit"
layout="topleft"
name="take_off">
<on_click
- function="Gear.OnClick"
- parameter="take_off"/>
+ function="Gear.TakeOff" />
<on_enable
function="Gear.OnEnable"
parameter="take_off" />
</menu_item_call>
+
+ <menu_item_separator />
+ <!-- copied (with minor modifications) from menu_inventory_add.xml -->
+ <!-- *TODO: generate dynamically? -->
+ <menu
+ height="175"
+ label="New Clothes"
+ layout="topleft"
+ left_delta="0"
+ mouse_opaque="false"
+ name="New Clothes"
+ top_pad="514"
+ width="125">
+ <menu_item_call
+ label="New Shirt"
+ layout="topleft"
+ name="New Shirt">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="shirt" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Pants"
+ layout="topleft"
+ name="New Pants">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="pants" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Shoes"
+ layout="topleft"
+ name="New Shoes">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="shoes" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Socks"
+ layout="topleft"
+ name="New Socks">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="socks" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Jacket"
+ layout="topleft"
+ name="New Jacket">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="jacket" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Skirt"
+ layout="topleft"
+ name="New Skirt">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="skirt" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Gloves"
+ layout="topleft"
+ name="New Gloves">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="gloves" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Undershirt"
+ layout="topleft"
+ name="New Undershirt">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="undershirt" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Underpants"
+ layout="topleft"
+ name="New Underpants">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="underpants" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Alpha"
+ layout="topleft"
+ name="New Alpha">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="alpha" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Tattoo"
+ layout="topleft"
+ name="New Tattoo">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="tattoo" />
+ </menu_item_call>
+ </menu>
+ <menu
+ height="85"
+ label="New Body Parts"
+ layout="topleft"
+ left_delta="0"
+ mouse_opaque="false"
+ name="New Body Parts"
+ top_pad="514"
+ width="118">
+ <menu_item_call
+ label="New Shape"
+ layout="topleft"
+ name="New Shape">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="shape" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Skin"
+ layout="topleft"
+ name="New Skin">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="skin" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Hair"
+ layout="topleft"
+ name="New Hair">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="hair" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Eyes"
+ layout="topleft"
+ name="New Eyes">
+ <menu_item_call.on_click
+ function="Gear.Create"
+ parameter="eyes" />
+ </menu_item_call>
+ </menu>
+ <!-- copied from menu_inventory_add.xml -->
+
<menu_item_separator />
<menu_item_call
label="Rename"
layout="topleft"
name="rename">
<on_click
- function="Gear.OnClick"
- parameter="rename"/>
+ function="Gear.Rename" />
<on_enable
function="Gear.OnEnable"
parameter="rename" />
@@ -41,10 +184,9 @@
layout="topleft"
name="delete_outfit">
<on_click
- function="Gear.OnClick"
- parameter="delete_outfit"/>
+ function="Gear.Delete" />
<on_enable
function="Gear.OnEnable"
- parameter="delete_outfit" />
+ parameter="delete" />
</menu_item_call>
</menu>
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 8f3e62157a..67559638d9 100644
--- a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
+++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
@@ -8,6 +8,9 @@
name="wear_replace">
<on_click
function="Outfit.WearReplace" />
+ <on_enable
+ function="Outfit.OnEnable"
+ parameter="wear_replace" />
</menu_item_call>
<menu_item_call
label="Wear - Add to Current Outfit"
@@ -15,13 +18,29 @@
name="wear_add">
<on_click
function="Outfit.WearAdd" />
+ <on_enable
+ function="Outfit.OnEnable"
+ parameter="wear_add" />
</menu_item_call>
<menu_item_call
- label="Take Off - Remove Current Outfit"
+ label="Take Off - Remove from Current Outfit"
layout="topleft"
name="take_off">
<on_click
function="Outfit.TakeOff" />
+ <on_enable
+ function="Outfit.OnEnable"
+ parameter="take_off" />
+ </menu_item_call>
+ <menu_item_call
+ label="Edit Outfit"
+ layout="topleft"
+ name="edit">
+ <on_click
+ function="Outfit.Edit" />
+ <on_enable
+ function="Outfit.OnEnable"
+ parameter="edit" />
</menu_item_call>
<menu_item_separator />
<menu_item_call
@@ -30,6 +49,9 @@
name="rename">
<on_click
function="Outfit.Rename" />
+ <on_enable
+ function="Outfit.OnEnable"
+ parameter="rename" />
</menu_item_call>
<menu_item_call
label="Delete Outfit"
@@ -37,5 +59,8 @@
name="delete">
<on_click
function="Outfit.Delete" />
+ <on_enable
+ function="Outfit.OnEnable"
+ parameter="delete" />
</menu_item_call>
</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
index 7ea7eaade5..e645702f93 100644
--- a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
+++ b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
@@ -9,22 +9,27 @@
function="Wearable.Wear" />
</menu_item_call>
<menu_item_call
+ label="Take Off / Detach"
+ layout="topleft"
+ name="take_off_or_detach">
+ <on_click
+ function="Wearable.TakeOffDetach" />
+ </menu_item_call>
+ <menu_item_call
label="Detach"
layout="topleft"
name="detach">
<on_click
function="Attachment.Detach" />
</menu_item_call>
-<!-- *TODO: implement the submenus
- <menu
- label="Attach to"
+ <context_menu
+ label="Attach to ▶"
layout="topleft"
- name="attach_to" />
- <menu
- label="Attach to HUD"
+ name="wearable_attach_to" />
+ <context_menu
+ label="Attach to HUD ▶"
layout="topleft"
- name="attach_to_hud" />
--->
+ name="wearable_attach_to_hud" />
<menu_item_call
label="Object Profile"
layout="topleft"
@@ -37,16 +42,14 @@
layout="topleft"
name="take_off">
<on_click
- function="Clothing.TakeOff"
- parameter="take_off"/>
+ function="Clothing.TakeOff" />
</menu_item_call>
<menu_item_call
label="Edit"
layout="topleft"
name="edit">
<on_click
- function="Wearable.Edit"
- parameter="edit"/>
+ function="Wearable.Edit" />
</menu_item_call>
<menu_item_call
label="Show Original"
@@ -55,4 +58,12 @@
<on_click
function="Wearable.ShowOriginal" />
</menu_item_call>
+ <menu_item_call
+ label="Create New"
+ layout="topleft"
+ name="create_new"
+ translate="false">
+ <on_click
+ function="Wearable.CreateNew" />
+ </menu_item_call>
</context_menu>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 2590924b58..5ead756d20 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -2070,6 +2070,28 @@ Would you be my friend?
<notification
icon="alertmodal.tga"
+ label="Rename Outfit"
+ name="RenameOutfit"
+ type="alertmodal">
+ New outfit name:
+ <form name="form">
+ <input name="new_name" type="text">
+ [NAME]
+ </input>
+ <button
+ default="true"
+ index="0"
+ name="Offer"
+ text="OK"/>
+ <button
+ index="1"
+ name="Cancel"
+ text="Cancel"/>
+ </form>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="RemoveFromFriends"
type="alertmodal">
Do you want to remove [FIRST_NAME] [LAST_NAME] from your Friends List?
diff --git a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
index 68c364680e..5f34c24bca 100644
--- a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
+++ b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
@@ -9,6 +9,7 @@
name="cof_wearables"
width="311">
<accordion
+ fit_parent="true"
follows="all"
height="200"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_eyes.xml b/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
index 4149a0b06f..f173a2f3cb 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_eyes.xml
@@ -51,6 +51,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_gloves.xml b/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
index 94fd2f9080..a490f27b9f 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_gloves.xml
@@ -65,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_hair.xml b/indra/newview/skins/default/xui/en/panel_edit_hair.xml
index 9b60e83387..6bb5d2fa9b 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_hair.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_hair.xml
@@ -51,6 +51,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_jacket.xml b/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
index 248ae9fe04..929cdffb3d 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_jacket.xml
@@ -80,6 +80,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_pants.xml b/indra/newview/skins/default/xui/en/panel_edit_pants.xml
index 3ed1df2399..f22cf983aa 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_pants.xml
@@ -65,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shirt.xml b/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
index e088aa05ac..85823073b5 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shirt.xml
@@ -65,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_shoes.xml b/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
index e079047a86..b26fde68f1 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_shoes.xml
@@ -65,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_skin.xml b/indra/newview/skins/default/xui/en/panel_edit_skin.xml
index 9158685c40..45591ba2ad 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_skin.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_skin.xml
@@ -85,6 +85,7 @@
width="313">
<accordion
layout="topleft"
+ fit_parent="true"
follows="all"
height ="300"
left="0"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_skirt.xml b/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
index 87f3270b31..bb8e0dca07 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_skirt.xml
@@ -65,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_socks.xml b/indra/newview/skins/default/xui/en/panel_edit_socks.xml
index 5bd99969a2..d813d94d93 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_socks.xml
@@ -65,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_underpants.xml b/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
index bbe5230341..19225e9757 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_underpants.xml
@@ -65,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
index a79c1b9eaa..720a55dcc2 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_undershirt.xml
@@ -65,6 +65,7 @@
top_pad="10"
width="313">
<accordion
+ fit_parent="true"
follows="all"
height ="300"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml
index fcc998c08a..57ac79686d 100644
--- a/indra/newview/skins/default/xui/en/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml
@@ -320,6 +320,7 @@
value="unknown"
width="268" />
<accordion
+ fit_parent="true"
follows="all"
height="223"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 8dd5d64e71..9d7079a495 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -318,6 +318,10 @@
<!-- For use when we do not have land type back from the server -->
<string name="land_type_unknown">(unknown)</string>
+ <!-- For land type back from the simulator -->
+ <string name="Estate / Full Region">Estate / Full Region</string>
+ <string name="Mainland / Full Region">Mainland / Full Region</string>
+
<!-- File load/save dialogs -->
<string name="all_files">All Files</string>
<string name="sound_files">Sounds</string>
@@ -1826,6 +1830,7 @@ Clears (deletes) the media and all params from the given face.
<!-- Wearable List-->
<string name="NewWearable">New [WEARABLE_ITEM]</string>
+ <string name="CreateNewWearable">Create [WEARABLE_TYPE]</string>
<!-- LLGroupNotify -->
<!-- used in the construction of a Group Notice blue dialog box, buttons, tooltip etc. Seems to be no longer utilized by code in Viewer 2.0 -->
diff --git a/indra/newview/skins/default/xui/pl/floater_about_land.xml b/indra/newview/skins/default/xui/pl/floater_about_land.xml
index e4908deb07..163868f200 100644
--- a/indra/newview/skins/default/xui/pl/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/pl/floater_about_land.xml
@@ -196,13 +196,13 @@ Idź do Świat &gt; O Posiadłości albo wybierz inną posiadłość żeby pokaz
<text name="resellable_lbl">
Odsprzedaj:
</text>
- <text left="115" name="resellable_clause" width="338">
+ <text left="115" name="resellable_clause">
Posiadłość zakupiona w tym Regionie nie może być odsprzedana.
</text>
<text name="changeable_lbl">
Podziel:
</text>
- <text left="115" name="changeable_clause" width="338">
+ <text left="115" name="changeable_clause">
Posiadłość zakupiona w tym Regionie nie może być
łączona/dzielona.
</text>