From e96544ff266849207adfc3823adfc2dcfe42ce72 Mon Sep 17 00:00:00 2001 From: Igor Borovkov Date: Mon, 14 Jun 2010 15:04:06 +0300 Subject: EXT-7742 FIXED panel outfit edit: added a separate dropdown for the list view - added a separate filter combobox for the list view containing lots of items, all types of wearables, separated clothing and bodyparts items - comboboxes are linked to the appropriate view, only one is shown - got rid of excluding links in the folder view - minor refactoring Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/573/ --HG-- branch : product-engine --- indra/newview/llinventoryfunctions.h | 26 ++++ indra/newview/llpaneloutfitedit.cpp | 145 ++++++++++++++------- indra/newview/llpaneloutfitedit.h | 73 ++++++++--- .../skins/default/xui/en/panel_outfit_edit.xml | 20 ++- 4 files changed, 198 insertions(+), 66 deletions(-) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index c82ebd1439..93c56e1b8a 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -266,6 +266,32 @@ public: }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindNonLinksByMask +// +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindByMask : public LLInventoryCollectFunctor +{ +public: + LLFindByMask(U64 mask) + : mFilterMask(mask) + {} + + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if(item && (mFilterMask & (1LL << item->getInventoryType())) ) + { + return true; + } + + return false; + } + +private: + U64 mFilterMask; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFindNonLinksByMask // diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 32b209dd0d..1454a2f6af 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -65,6 +65,7 @@ #include "llsaveoutfitcombobtn.h" #include "llscrolllistctrl.h" #include "lltextbox.h" +#include "lltrans.h" #include "lluictrlfactory.h" #include "llsdutil.h" #include "llsidepanelappearance.h" @@ -188,9 +189,8 @@ LLPanelOutfitEdit::LLPanelOutfitEdit() mCOFDragAndDropObserver(NULL), mInitialized(false), mAddWearablesPanel(NULL), - mWearableListMaskCollector(NULL), - mWearableListTypeCollector(NULL), - mFilterComboBox(NULL) + mFolderViewFilterCmbBox(NULL), + mListViewFilterCmbBox(NULL) { mSavedFolderState = new LLSaveFolderState(); mSavedFolderState->setApply(FALSE); @@ -202,12 +202,11 @@ LLPanelOutfitEdit::LLPanelOutfitEdit() observer.addOutfitLockChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this)); observer.addCOFChangedCallback(boost::bind(&LLPanelOutfitEdit::update, this)); - mLookItemTypes.reserve(NUM_LOOK_ITEM_TYPES); - for (U32 i = 0; i < NUM_LOOK_ITEM_TYPES; i++) + mFolderViewItemTypes.reserve(NUM_FOLDER_VIEW_ITEM_TYPES); + for (U32 i = 0; i < NUM_FOLDER_VIEW_ITEM_TYPES; i++) { - mLookItemTypes.push_back(LLLookItemType()); + mFolderViewItemTypes.push_back(LLLookItemType()); } - } @@ -217,17 +216,40 @@ LLPanelOutfitEdit::~LLPanelOutfitEdit() delete mCOFDragAndDropObserver; - delete mWearableListMaskCollector; - delete mWearableListTypeCollector; + while (!mListViewItemTypes.empty()) { + delete mListViewItemTypes.back(); + mListViewItemTypes.pop_back(); + } } BOOL LLPanelOutfitEdit::postBuild() { // gInventory.isInventoryUsable() no longer needs to be tested per Richard's fix for race conditions between inventory and panels - - mLookItemTypes[LIT_ALL] = LLLookItemType(getString("Filter.All"), ALL_ITEMS_MASK); - mLookItemTypes[LIT_WEARABLE] = LLLookItemType(getString("Filter.Clothes/Body"), WEARABLE_MASK); - mLookItemTypes[LIT_ATTACHMENT] = LLLookItemType(getString("Filter.Objects"), ATTACHMENT_MASK); + + mFolderViewItemTypes[FVIT_ALL] = LLLookItemType(getString("Filter.All"), ALL_ITEMS_MASK); + mFolderViewItemTypes[FVIT_WEARABLE] = LLLookItemType(getString("Filter.Clothes/Body"), WEARABLE_MASK); + mFolderViewItemTypes[FVIT_ATTACHMENT] = LLLookItemType(getString("Filter.Objects"), ATTACHMENT_MASK); + + //order is important, see EListViewItemType for order information + mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.All"), new LLFindByMask(ALL_ITEMS_MASK))); + mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Clothing"), new LLIsType(LLAssetType::AT_CLOTHING))); + mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Bodyparts"), new LLIsType(LLAssetType::AT_BODYPART))); + mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Objects"), new LLFindByMask(ATTACHMENT_MASK)));; + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shape"), new LLFindActualWearablesOfType(LLWearableType::WT_SHAPE))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skin"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIN))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("hair"), new LLFindActualWearablesOfType(LLWearableType::WT_HAIR))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("eyes"), new LLFindActualWearablesOfType(LLWearableType::WT_EYES))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SHIRT))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("pants"), new LLFindActualWearablesOfType(LLWearableType::WT_PANTS))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shoes"), new LLFindActualWearablesOfType(LLWearableType::WT_SHOES))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("socks"), new LLFindActualWearablesOfType(LLWearableType::WT_SOCKS))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("jacket"), new LLFindActualWearablesOfType(LLWearableType::WT_JACKET))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("gloves"), new LLFindActualWearablesOfType(LLWearableType::WT_GLOVES))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("undershirt"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERSHIRT))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("underpants"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERPANTS))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIRT))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("alpha"), new LLFindActualWearablesOfType(LLWearableType::WT_ALPHA))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("tattoo"), new LLFindActualWearablesOfType(LLWearableType::WT_TATTOO))); mCurrentOutfitName = getChild("curr_outfit_name"); mStatus = getChild("status"); @@ -252,7 +274,7 @@ BOOL LLPanelOutfitEdit::postBuild() mAddWearablesPanel = getChild("add_wearables_panel"); - mInventoryItemsPanel = getChild("inventory_items"); + mInventoryItemsPanel = getChild("folder_view"); mInventoryItemsPanel->setFilterTypes(ALL_ITEMS_MASK); mInventoryItemsPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); mInventoryItemsPanel->setSelectCallback(boost::bind(&LLPanelOutfitEdit::onInventorySelectionChange, this, _1, _2)); @@ -260,15 +282,24 @@ BOOL LLPanelOutfitEdit::postBuild() mCOFDragAndDropObserver = new LLCOFDragAndDropObserver(mInventoryItemsPanel->getModel()); - mFilterComboBox = getChild("filter_wearables_combobox"); - mFilterComboBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onTypeFilterChanged, this, _1)); - mFilterComboBox->removeall(); - for (U32 i = 0; i < mLookItemTypes.size(); ++i) + mFolderViewFilterCmbBox = getChild("folder_view_filter_combobox"); + mFolderViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onFolderViewFilterCommitted, this, _1)); + mFolderViewFilterCmbBox->removeall(); + for (U32 i = 0; i < mFolderViewItemTypes.size(); ++i) { - mFilterComboBox->add(mLookItemTypes[i].displayName); + mFolderViewFilterCmbBox->add(mFolderViewItemTypes[i].displayName); } - mFilterComboBox->setCurrentByIndex(LIT_ALL); + mFolderViewFilterCmbBox->setCurrentByIndex(FVIT_ALL); + mListViewFilterCmbBox = getChild("list_view_filter_combobox"); + mListViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onListViewFilterCommitted, this, _1)); + mListViewFilterCmbBox->removeall(); + for (U32 i = 0; i < mListViewItemTypes.size(); ++i) + { + mListViewFilterCmbBox->add(mListViewItemTypes[i]->displayName); + } + mListViewFilterCmbBox->setCurrentByIndex(LVIT_ALL); + mSearchFilter = getChild("look_item_filter"); mSearchFilter->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onSearchEdit, this, _2)); @@ -283,11 +314,8 @@ BOOL LLPanelOutfitEdit::postBuild() childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance())); - mWearableListMaskCollector = new LLFindNonLinksByMask(ALL_ITEMS_MASK); - mWearableListTypeCollector = new LLFindActualWearablesOfType(LLWearableType::WT_NONE); - - mWearableItemsPanel = getChild("filtered_wearables_panel"); - mWearableItemsList = getChild("filtered_wearables_list"); + mWearablesListViewPanel = getChild("filtered_wearables_panel"); + mWearableItemsList = getChild("list_view"); mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this)); return TRUE; @@ -300,7 +328,7 @@ void LLPanelOutfitEdit::onOpen(const LLSD& key) { // *TODO: this method is called even panel is not visible to user because its parent layout panel is hidden. // So, we can defer initializing a bit. - mWearableListManager = new LLFilteredWearableListManager(mWearableItemsList, mWearableListMaskCollector); + mWearableListManager = new LLFilteredWearableListManager(mWearableItemsList, mListViewItemTypes[LVIT_ALL]->collector); mWearableListManager->populateList(); displayCurrentOutfit(); mInitialized = true; @@ -328,13 +356,17 @@ void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables) childSetValue("show_add_wearables_btn", show_add_wearables); - childSetVisible("filter_wearables_combobox", show_add_wearables); + updateFiltersVisibility(); childSetVisible("filter_button", show_add_wearables); //search filter should be disabled if (!show_add_wearables) { childSetValue("filter_button", false); + + mFolderViewFilterCmbBox->setVisible(false); + mListViewFilterCmbBox->setVisible(false); + showWearablesFilter(); } @@ -358,33 +390,40 @@ void LLPanelOutfitEdit::showWearablesFilter() void LLPanelOutfitEdit::showWearablesListView() { - if(switchPanels(mInventoryItemsPanel, mWearableItemsPanel)) + if(switchPanels(mInventoryItemsPanel, mWearablesListViewPanel)) { mFolderViewBtn->setToggleState(FALSE); mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign()); mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign()); + updateFiltersVisibility(); } mListViewBtn->setToggleState(TRUE); } void LLPanelOutfitEdit::showWearablesFolderView() { - if(switchPanels(mWearableItemsPanel, mInventoryItemsPanel)) + if(switchPanels(mWearablesListViewPanel, mInventoryItemsPanel)) { mListViewBtn->setToggleState(FALSE); mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign()); mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign()); + updateFiltersVisibility(); } mFolderViewBtn->setToggleState(TRUE); } -void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl) +void LLPanelOutfitEdit::updateFiltersVisibility() { - U32 curr_filter_type = mFilterComboBox->getCurrentIndex(); - mInventoryItemsPanel->setFilterTypes(mLookItemTypes[curr_filter_type].inventoryMask); + mListViewFilterCmbBox->setVisible(mWearablesListViewPanel->getVisible()); + mFolderViewFilterCmbBox->setVisible(mInventoryItemsPanel->getVisible()); +} - mWearableListMaskCollector->setFilterMask(mLookItemTypes[curr_filter_type].inventoryMask); - mWearableListManager->setFilterCollector(mWearableListMaskCollector); +void LLPanelOutfitEdit::onFolderViewFilterCommitted(LLUICtrl* ctrl) +{ + S32 curr_filter_type = mFolderViewFilterCmbBox->getCurrentIndex(); + if (curr_filter_type < 0) return; + + mInventoryItemsPanel->setFilterTypes(mFolderViewItemTypes[curr_filter_type].inventoryMask); mSavedFolderState->setApply(TRUE); mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); @@ -396,6 +435,14 @@ void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl) LLInventoryModelBackgroundFetch::instance().start(); } +void LLPanelOutfitEdit::onListViewFilterCommitted(LLUICtrl* ctrl) +{ + S32 curr_filter_type = mListViewFilterCmbBox->getCurrentIndex(); + if (curr_filter_type < 0) return; + + mWearableListManager->setFilterCollector(mListViewItemTypes[curr_filter_type]->collector); +} + void LLPanelOutfitEdit::onSearchEdit(const std::string& string) { if (mSearchString != string) @@ -453,7 +500,7 @@ void LLPanelOutfitEdit::onAddToOutfitClicked(void) selected_id = listenerp->getUUID(); } - else if (mWearableItemsPanel->getVisible()) + else if (mWearablesListViewPanel->getVisible()) { selected_id = mWearableItemsList->getSelectedUUID(); } @@ -537,10 +584,16 @@ void LLPanelOutfitEdit::onInventorySelectionChange(const std::dequesetCurrentByIndex(type); - mFilterComboBox->onCommit(); + mFolderViewFilterCmbBox->setCurrentByIndex(type); + mFolderViewFilterCmbBox->onCommit(); +} + +void LLPanelOutfitEdit::applyListViewFilter(EListViewItemType type) +{ + mListViewFilterCmbBox->setCurrentByIndex(type); + mListViewFilterCmbBox->onCommit(); } void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) @@ -561,14 +614,15 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) if (nothing_selected) { showWearablesFolderView(); + applyFolderViewFilter(FVIT_ALL); } if (more_than_one_selected) { showWearablesListView(); + applyListViewFilter(LVIT_ALL); } - - applyFilter(LIT_ALL); + return; } @@ -585,7 +639,7 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) { //Inventory misses an item with non-zero id showWearablesListView(); - applyFilter(LIT_ALL); + applyListViewFilter(LVIT_ALL); return; } @@ -595,14 +649,13 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) { //single clothing or bodypart item is selected showFilteredWearablesListView(item->getWearableType()); - mFilterComboBox->setLabel(getString("Filter.Custom")); return; } else { //attachment is selected showWearablesListView(); - applyFilter(LIT_ATTACHMENT); + applyListViewFilter(LVIT_ATTACHMENT); return; } } @@ -740,11 +793,11 @@ void LLPanelOutfitEdit::onAddMoreButtonClicked() void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type) { - mFilterComboBox->setLabel(getString("Filter.Custom")); - mWearableListTypeCollector->setType(type); - mWearableListManager->setFilterCollector(mWearableListTypeCollector); showAddWearablesPanel(true); showWearablesListView(); + + //e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE + applyListViewFilter((EListViewItemType) (LVIT_SHAPE + type)); } diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index d19ede04f1..56c6c6d680 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -42,6 +42,7 @@ #include "llremoteparcelrequest.h" #include "llinventory.h" +#include "llinventoryfunctions.h" #include "llinventoryitemslist.h" #include "llinventorymodel.h" @@ -69,21 +70,59 @@ class LLPanelOutfitEdit : public LLPanel LOG_CLASS(LLPanelOutfitEdit); public: - // NOTE: initialize mLookItemTypes at the index of any new enum you add in the LLPanelOutfitEdit() constructor - typedef enum e_look_item_type + // NOTE: initialize mFolderViewItemTypes at the index of any new enum you add in the LLPanelOutfitEdit() constructor + typedef enum e_folder_view_item_type { - LIT_ALL = 0, - LIT_WEARABLE, // clothing or shape - LIT_ATTACHMENT, - NUM_LOOK_ITEM_TYPES - } ELookItemType; + FVIT_ALL = 0, + FVIT_WEARABLE, // clothing or shape + FVIT_ATTACHMENT, + NUM_FOLDER_VIEW_ITEM_TYPES + } EFolderViewItemType; + //should reflect order from LLWearableType::EType + typedef enum e_list_view_item_type + { + LVIT_ALL = 0, + LVIT_CLOTHING, + LVIT_BODYPART, + LVIT_ATTACHMENT, + LVIT_SHAPE, + LVIT_SKIN, + LVIT_HAIR, + LVIT_EYES, + LVIT_SHIRT, + LVIT_PANTS, + LVIT_SHOES, + LVIT_SOCKS, + LVIT_JACKET, + LVIT_GLOVES, + LVIT_UNDERSHIRT, + LVIT_UNDERPANTS, + LVIT_SKIRT, + LVIT_ALPHA, + LVIT_TATTOO, + NUM_LIST_VIEW_ITEM_TYPES + } EListViewItemType; + struct LLLookItemType { std::string displayName; U64 inventoryMask; LLLookItemType() : displayName("NONE"), inventoryMask(0) {} LLLookItemType(std::string name, U64 mask) : displayName(name), inventoryMask(mask) {} }; + + struct LLFilterItem { + std::string displayName; + LLInventoryCollectFunctor* collector; + LLFilterItem() : displayName("NONE"), collector(NULL) {} + LLFilterItem(std::string name, LLInventoryCollectFunctor* _collector) : displayName(name), collector(_collector) {} + ~LLFilterItem() { delete collector; } + + //the struct is not supposed to by copied, either way the destructor kills collector + //LLPointer is not used as it requires LLInventoryCollectFunctor to extend LLRefCount what it doesn't do + private: + LLFilterItem(const LLFilterItem& filter_item) {}; + }; LLPanelOutfitEdit(); /*virtual*/ ~LLPanelOutfitEdit(); @@ -101,12 +140,16 @@ public: void showWearablesListView(); void showWearablesFolderView(); - void onTypeFilterChanged(LLUICtrl* ctrl); + void updateFiltersVisibility(); + + void onFolderViewFilterCommitted(LLUICtrl* ctrl); + void onListViewFilterCommitted(LLUICtrl* ctrl); void onSearchEdit(const std::string& string); void onInventorySelectionChange(const std::deque &items, BOOL user_action); void onAddToOutfitClicked(void); - void applyFilter(e_look_item_type type); + void applyFolderViewFilter(EFolderViewItemType type); + void applyListViewFilter(EListViewItemType type); /** * Filter items in views of Add Wearables Panel and show appropriate view depending on currently selected COF item(s) @@ -159,18 +202,18 @@ private: LLButton* mFolderViewBtn; LLButton* mListViewBtn; LLPanel* mAddWearablesPanel; - LLComboBox* mFilterComboBox; - - LLFindNonLinksByMask* mWearableListMaskCollector; - LLFindWearablesOfType* mWearableListTypeCollector; + + LLComboBox* mFolderViewFilterCmbBox; + LLComboBox* mListViewFilterCmbBox; LLFilteredWearableListManager* mWearableListManager; LLInventoryItemsList* mWearableItemsList; - LLPanel* mWearableItemsPanel; + LLPanel* mWearablesListViewPanel; LLCOFDragAndDropObserver* mCOFDragAndDropObserver; - std::vector mLookItemTypes; + std::vector mFolderViewItemTypes; + std::vector mListViewItemTypes; LLCOFWearables* mCOFWearables; LLMenuGL* mGearMenu; diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml index df9dfc6ac3..ed3b176267 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml @@ -51,7 +51,8 @@ - + +