summaryrefslogtreecommitdiff
path: root/indra/newview/llpaneloutfitedit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llpaneloutfitedit.cpp')
-rw-r--r--indra/newview/llpaneloutfitedit.cpp292
1 files changed, 256 insertions, 36 deletions
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 17e7965ab7..54b0805a6c 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -2,31 +2,25 @@
* @file llpaneloutfitedit.cpp
* @brief Displays outfit edit information in Side Tray.
*
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
* 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
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * 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
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * 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.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -86,6 +80,11 @@ const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
static const std::string REVERT_BTN("revert_btn");
+
+///////////////////////////////////////////////////////////////////////////////
+// LLShopURLDispatcher
+///////////////////////////////////////////////////////////////////////////////
+
class LLShopURLDispatcher
{
public:
@@ -145,6 +144,10 @@ std::string LLShopURLDispatcher::resolveURL(LLAssetType::EType asset_type, ESex
return gSavedSettings.getString(setting_name);
}
+///////////////////////////////////////////////////////////////////////////////
+// LLPanelOutfitEditGearMenu
+///////////////////////////////////////////////////////////////////////////////
+
class LLPanelOutfitEditGearMenu
{
public:
@@ -160,7 +163,6 @@ public:
if (menu)
{
populateCreateWearableSubmenus(menu);
- menu->buildDrawLabels();
}
return menu;
@@ -209,6 +211,147 @@ private:
}
};
+///////////////////////////////////////////////////////////////////////////////
+// LLAddWearablesGearMenu
+///////////////////////////////////////////////////////////////////////////////
+
+class LLAddWearablesGearMenu : public LLInitClass<LLAddWearablesGearMenu>
+{
+public:
+ static LLMenuGL* create(LLWearableItemsList* flat_list, LLInventoryPanel* inventory_panel)
+ {
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+ llassert(flat_list);
+ llassert(inventory_panel);
+
+ LLHandle<LLView> flat_list_handle = flat_list->getHandle();
+ LLHandle<LLPanel> inventory_panel_handle = inventory_panel->getHandle();
+
+ registrar.add("AddWearable.Gear.Sort", boost::bind(onSort, flat_list_handle, inventory_panel_handle, _2));
+ enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2));
+ enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2));
+
+ LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+ "menu_add_wearable_gear.xml",
+ LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+
+ return menu;
+ }
+
+private:
+ static void onSort(LLHandle<LLView> flat_list_handle,
+ LLHandle<LLPanel> inventory_panel_handle,
+ LLSD::String sort_order_str)
+ {
+ if (flat_list_handle.isDead() || inventory_panel_handle.isDead()) return;
+
+ LLWearableItemsList* flat_list = dynamic_cast<LLWearableItemsList*>(flat_list_handle.get());
+ LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
+
+ if (!flat_list || !inventory_panel) return;
+
+ LLWearableItemsList::ESortOrder sort_order;
+
+ if ("by_most_recent" == sort_order_str)
+ {
+ sort_order = LLWearableItemsList::E_SORT_BY_MOST_RECENT;
+ }
+ else if ("by_name" == sort_order_str)
+ {
+ sort_order = LLWearableItemsList::E_SORT_BY_NAME;
+ }
+ else if ("by_type" == sort_order_str)
+ {
+ sort_order = LLWearableItemsList::E_SORT_BY_TYPE_NAME;
+ }
+ else
+ {
+ llwarns << "Unrecognized sort order action" << llendl;
+ return;
+ }
+
+ if (inventory_panel->getVisible())
+ {
+ inventory_panel->setSortOrder(sort_order);
+ }
+ else
+ {
+ flat_list->setSortOrder(sort_order);
+ }
+ }
+
+ static bool onCheck(LLHandle<LLView> flat_list_handle,
+ LLHandle<LLPanel> inventory_panel_handle,
+ LLSD::String sort_order_str)
+ {
+ if (flat_list_handle.isDead() || inventory_panel_handle.isDead()) return false;
+
+ LLWearableItemsList* flat_list = dynamic_cast<LLWearableItemsList*>(flat_list_handle.get());
+ LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
+
+ if (!inventory_panel || !flat_list) return false;
+
+ // Inventory panel uses its own sort order independent from
+ // flat list view so this flag is used to distinguish between
+ // currently visible "tree" or "flat" representation of inventory.
+ bool inventory_tree_visible = inventory_panel->getVisible();
+
+ if (inventory_tree_visible)
+ {
+ U32 sort_order = inventory_panel->getSortOrder();
+
+ if ("by_most_recent" == sort_order_str)
+ {
+ return LLWearableItemsList::E_SORT_BY_MOST_RECENT & sort_order;
+ }
+ else if ("by_name" == sort_order_str)
+ {
+ // If inventory panel is not sorted by date then it is sorted by name.
+ return LLWearableItemsList::E_SORT_BY_MOST_RECENT & ~sort_order;
+ }
+ llwarns << "Unrecognized inventory panel sort order" << llendl;
+ }
+ else
+ {
+ LLWearableItemsList::ESortOrder sort_order = flat_list->getSortOrder();
+
+ if ("by_most_recent" == sort_order_str)
+ {
+ return LLWearableItemsList::E_SORT_BY_MOST_RECENT == sort_order;
+ }
+ else if ("by_name" == sort_order_str)
+ {
+ return LLWearableItemsList::E_SORT_BY_NAME == sort_order;
+ }
+ else if ("by_type" == sort_order_str)
+ {
+ return LLWearableItemsList::E_SORT_BY_TYPE_NAME == sort_order;
+ }
+ llwarns << "Unrecognized wearable list sort order" << llendl;
+ }
+ return false;
+ }
+
+ static bool onVisible(LLHandle<LLPanel> inventory_panel_handle,
+ LLSD::String sort_order_str)
+ {
+ if (inventory_panel_handle.isDead()) return false;
+
+ LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
+
+ // Enable sorting by type only for the flat list of items
+ // because inventory panel doesn't support this kind of sorting.
+ return ( "by_type" == sort_order_str )
+ && ( !inventory_panel || !inventory_panel->getVisible() );
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// LLCOFDragAndDropObserver
+///////////////////////////////////////////////////////////////////////////////
+
class LLCOFDragAndDropObserver : public LLInventoryAddItemByAssetObserver
{
public:
@@ -244,12 +387,17 @@ void LLCOFDragAndDropObserver::done()
LLAppearanceMgr::instance().updateAppearanceFromCOF();
}
+///////////////////////////////////////////////////////////////////////////////
+// LLPanelOutfitEdit
+///////////////////////////////////////////////////////////////////////////////
+
LLPanelOutfitEdit::LLPanelOutfitEdit()
: LLPanel(),
mSearchFilter(NULL),
mCOFWearables(NULL),
mInventoryItemsPanel(NULL),
mGearMenu(NULL),
+ mAddWearablesGearMenu(NULL),
mCOFDragAndDropObserver(NULL),
mInitialized(false),
mAddWearablesPanel(NULL),
@@ -284,8 +432,6 @@ LLPanelOutfitEdit::~LLPanelOutfitEdit()
delete mCOFDragAndDropObserver;
- delete mWearableListViewItemsComparator;
-
while (!mListViewItemTypes.empty()) {
delete mListViewItemTypes.back();
mListViewItemTypes.pop_back();
@@ -404,10 +550,11 @@ BOOL LLPanelOutfitEdit::postBuild()
mWearableListViewItemsComparator->setOrder(LLAssetType::AT_CLOTHING, LLWearableItemTypeNameComparator::ORDER_RANK_1, false, true);
mWearablesListViewPanel = getChild<LLPanel>("filtered_wearables_panel");
- mWearableItemsList = getChild<LLInventoryItemsList>("list_view");
+ mWearableItemsList = getChild<LLWearableItemsList>("list_view");
mWearableItemsList->setCommitOnSelectionChange(true);
mWearableItemsList->setCommitCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
mWearableItemsList->setDoubleClickCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this));
+
mWearableItemsList->setComparator(mWearableListViewItemsComparator);
mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this));
@@ -462,6 +609,17 @@ void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables)
showWearablesFilter();
+ /*
+ * By default AT_CLOTHING are sorted by (in in MY OUTFITS):
+ * - by type (types order determined in LLWearableType::EType)
+ * - each LLWearableType::EType by outer layer on top
+ *
+ * In Add More panel AT_CLOTHING should be sorted in a such way:
+ * - by type (types order determined in LLWearableType::EType)
+ * - each LLWearableType::EType by name (EXT-8205)
+ */
+ mWearableItemsList->setSortOrder(LLWearableItemsList::E_SORT_BY_TYPE_NAME);
+
// Reset mWearableItemsList position to top. See EXT-8180.
mWearableItemsList->goToTop();
}
@@ -623,11 +781,11 @@ void LLPanelOutfitEdit::onAddWearableClicked(void)
}
}
-void LLPanelOutfitEdit::onReplaceBodyPartMenuItemClicked(LLUUID selected_item_id)
+void LLPanelOutfitEdit::onReplaceMenuItemClicked(LLUUID selected_item_id)
{
LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
- if (item && item->getType() == LLAssetType::AT_BODYPART)
+ if (item)
{
showFilteredWearablesListView(item->getWearableType());
}
@@ -753,8 +911,14 @@ LLWearableType::EType LLPanelOutfitEdit::getWearableTypeByItemUUID(const LLUUID&
void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
{
LLUUID id_to_remove = mCOFWearables->getSelectedUUID();
-
+ LLWearableType::EType type = getWearableTypeByItemUUID(id_to_remove);
+
LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove);
+
+ if (!mCOFWearables->getSelectedItem())
+ {
+ mCOFWearables->selectClothing(type);
+ }
}
@@ -849,6 +1013,10 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
// | filter_type = expanded accordion_type
if (nothing_selected)
{
+ if (mInventoryItemsPanel->getVisible())
+ {
+ return;
+ }
showWearablesListView();
//selected accordion tab is more priority than expanded tab
@@ -863,7 +1031,7 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
LLUUID selected_item_id = mWearableItemsList->getSelectedUUID();
LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
if(item)
- {
+ {
showFilteredWearablesListView(item->getWearableType());
return;
}
@@ -882,7 +1050,7 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
applyListViewFilter(LVIT_BODYPART);
break;
case LLAssetType::AT_CLOTHING:
- default:
+ default:
applyListViewFilter(LVIT_CLOTHING);
break;
}
@@ -893,6 +1061,12 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
//resetting selection if more than one item is selected
if (more_than_one_selected)
{
+ if (mInventoryItemsPanel->getVisible())
+ {
+ applyFolderViewFilter(FVIT_ALL);
+ return;
+ }
+
showWearablesListView();
applyListViewFilter(LVIT_ALL);
return;
@@ -902,6 +1076,12 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
//filter wearables by a type represented by a dummy item
if (one_selected && is_dummy_item)
{
+ if (mInventoryItemsPanel->getVisible())
+ {
+ applyFolderViewFilter(FVIT_WEARABLE);
+ return;
+ }
+
onAddWearableClicked();
return;
}
@@ -909,6 +1089,11 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
LLViewerInventoryItem* item = gInventory.getItem(ids[0]);
if (!item && ids[0].notNull())
{
+ if (mInventoryItemsPanel->getVisible())
+ {
+ applyFolderViewFilter(FVIT_ALL);
+ return;
+ }
//Inventory misses an item with non-zero id
showWearablesListView();
applyListViewFilter(LVIT_ALL);
@@ -919,12 +1104,22 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
{
if (item->isWearableType())
{
+ if (mInventoryItemsPanel->getVisible())
+ {
+ applyFolderViewFilter(FVIT_WEARABLE);
+ return;
+ }
//single clothing or bodypart item is selected
showFilteredWearablesListView(item->getWearableType());
return;
}
else
{
+ if (mInventoryItemsPanel->getVisible())
+ {
+ applyFolderViewFilter(FVIT_ATTACHMENT);
+ return;
+ }
//attachment is selected
showWearablesListView();
applyListViewFilter(LVIT_ATTACHMENT);
@@ -1063,13 +1258,33 @@ void LLPanelOutfitEdit::resetAccordionState()
void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button)
{
- if(!mGearMenu)
+ LLMenuGL* menu = NULL;
+
+ if (mAddWearablesPanel->getVisible())
{
- mGearMenu = LLPanelOutfitEditGearMenu::create();
+ if (!mAddWearablesGearMenu)
+ {
+ mAddWearablesGearMenu = LLAddWearablesGearMenu::create(mWearableItemsList, mInventoryItemsPanel);
+ }
+
+ menu = mAddWearablesGearMenu;
}
+ else
+ {
+ if (!mGearMenu)
+ {
+ mGearMenu = LLPanelOutfitEditGearMenu::create();
+ }
+
+ menu = mGearMenu;
+ }
+
+ if (!menu) return;
- S32 menu_y = mGearMenu->getRect().getHeight() + clicked_button->getRect().getHeight();
- LLMenuGL::showPopup(clicked_button, mGearMenu, 0, menu_y);
+ menu->arrangeAndClear(); // update menu height
+ S32 menu_y = menu->getRect().getHeight() + clicked_button->getRect().getHeight();
+ menu->buildDrawLabels();
+ LLMenuGL::showPopup(clicked_button, menu, 0, menu_y);
}
void LLPanelOutfitEdit::onAddMoreButtonClicked()
@@ -1151,6 +1366,13 @@ void LLPanelOutfitEdit::getSelectedItemsUUID(uuid_vec_t& uuid_list)
void LLPanelOutfitEdit::onCOFChanged()
{
+ //the panel is only updated when is visible to a user
+
+ // BAP - this check has to be removed because otherwise item name
+ // changes made when the panel is not visible will not be
+ // propagated to the panel.
+ // if (!isInVisibleChain()) return;
+
update();
}
@@ -1178,8 +1400,6 @@ void LLPanelOutfitEdit::saveListSelection()
if(!selected_ids.size()) return;
- mWearableItemsList->resetSelection();
-
for (std::set<LLUUID>::const_iterator item_id = selected_ids.begin(); item_id != selected_ids.end(); ++item_id)
{
mWearableItemsList->selectItemByUUID(*item_id, true);