diff options
Diffstat (limited to 'indra/newview/llpaneloutfitedit.cpp')
-rw-r--r-- | indra/newview/llpaneloutfitedit.cpp | 354 |
1 files changed, 316 insertions, 38 deletions
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 8b9baef54a..74bb972eb0 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -42,6 +42,7 @@ #include "lloutfitobserver.h" #include "llcofwearables.h" #include "llfilteredwearablelist.h" +#include "llfolderviewitem.h" #include "llinventory.h" #include "llinventoryitemslist.h" #include "llviewercontrol.h" @@ -85,6 +86,11 @@ const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK; static const std::string REVERT_BTN("revert_btn"); + +/////////////////////////////////////////////////////////////////////////////// +// LLShopURLDispatcher +/////////////////////////////////////////////////////////////////////////////// + class LLShopURLDispatcher { public: @@ -144,6 +150,10 @@ std::string LLShopURLDispatcher::resolveURL(LLAssetType::EType asset_type, ESex return gSavedSettings.getString(setting_name); } +/////////////////////////////////////////////////////////////////////////////// +// LLPanelOutfitEditGearMenu +/////////////////////////////////////////////////////////////////////////////// + class LLPanelOutfitEditGearMenu { public: @@ -159,7 +169,6 @@ public: if (menu) { populateCreateWearableSubmenus(menu); - menu->buildDrawLabels(); } return menu; @@ -208,6 +217,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: @@ -243,12 +393,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), @@ -301,7 +456,7 @@ BOOL LLPanelOutfitEdit::postBuild() mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.All"), new LLFindNonLinksByMask(ALL_ITEMS_MASK))); mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Clothing"), new LLIsTypeActual(LLAssetType::AT_CLOTHING))); mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Bodyparts"), new LLIsTypeActual(LLAssetType::AT_BODYPART))); - mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Objects"), new LLFindByMask(ATTACHMENT_MASK)));; + mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Objects"), new LLFindNonLinksByMask(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))); @@ -326,7 +481,9 @@ BOOL LLPanelOutfitEdit::postBuild() childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL); childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesFolderView, this), NULL); + childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL); childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesListView, this), NULL); + childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL); childSetCommitCallback("wearables_gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL); childSetCommitCallback("gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL); childSetCommitCallback("shop_btn_1", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL); @@ -387,7 +544,7 @@ BOOL LLPanelOutfitEdit::postBuild() childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance())); 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)); @@ -429,35 +586,46 @@ void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables) { mAddWearablesPanel->setVisible(show_add_wearables); - childSetValue("show_add_wearables_btn", show_add_wearables); + getChild<LLUICtrl>("show_add_wearables_btn")->setValue(show_add_wearables); updateFiltersVisibility(); - childSetVisible("filter_button", show_add_wearables); + getChildView("filter_button")->setVisible( show_add_wearables); //search filter should be disabled if (!show_add_wearables) { - childSetValue("filter_button", false); + getChild<LLUICtrl>("filter_button")->setValue(false); mFolderViewFilterCmbBox->setVisible(false); mListViewFilterCmbBox->setVisible(false); 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(); } //switching button bars - childSetVisible("no_add_wearables_button_bar", !show_add_wearables); - childSetVisible("add_wearables_button_bar", show_add_wearables); + getChildView("no_add_wearables_button_bar")->setVisible( !show_add_wearables); + getChildView("add_wearables_button_bar")->setVisible( show_add_wearables); } void LLPanelOutfitEdit::showWearablesFilter() { - bool filter_visible = childGetValue("filter_button"); + bool filter_visible = getChild<LLUICtrl>("filter_button")->getValue(); - childSetVisible("filter_panel", filter_visible); + getChildView("filter_panel")->setVisible( filter_visible); if(!filter_visible) { @@ -474,9 +642,7 @@ void LLPanelOutfitEdit::showWearablesListView() { if(switchPanels(mInventoryItemsPanel, mWearablesListViewPanel)) { - mFolderViewBtn->setToggleState(FALSE); - mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign()); - mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign()); + updateWearablesPanelVerbButtons(); updateFiltersVisibility(); } mListViewBtn->setToggleState(TRUE); @@ -486,9 +652,7 @@ void LLPanelOutfitEdit::showWearablesFolderView() { if(switchPanels(mWearablesListViewPanel, mInventoryItemsPanel)) { - mListViewBtn->setToggleState(FALSE); - mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign()); - mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign()); + updateWearablesPanelVerbButtons(); updateFiltersVisibility(); } mFolderViewBtn->setToggleState(TRUE); @@ -609,11 +773,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()); } @@ -629,8 +793,17 @@ void LLPanelOutfitEdit::onShopButtonClicked() if (isAgentAvatarValid()) { // try to get wearable type from 'Add More' panel first (EXT-7639) - LLWearableType::EType type = getAddMorePanelSelectionType(); + selection_info_t selection_info = getAddMorePanelSelectionType(); + + LLWearableType::EType type = selection_info.first; + if (selection_info.second > 1) + { + // the second argument is not important in this case: generic market place will be opened + url = url_resolver.resolveURL(LLWearableType::WT_NONE, SEX_FEMALE); + } + else + { if (type == LLWearableType::WT_NONE) { type = getCOFWearablesSelectionType(); @@ -646,7 +819,9 @@ void LLPanelOutfitEdit::onShopButtonClicked() if (url.empty()) { - url = url_resolver.resolveURL(mCOFWearables->getExpandedAccordionAssetType(), sex); + url = url_resolver.resolveURL( + mCOFWearables->getExpandedAccordionAssetType(), sex); + } } } else @@ -685,9 +860,9 @@ LLWearableType::EType LLPanelOutfitEdit::getCOFWearablesSelectionType() const return type; } -LLWearableType::EType LLPanelOutfitEdit::getAddMorePanelSelectionType() const +LLPanelOutfitEdit::selection_info_t LLPanelOutfitEdit::getAddMorePanelSelectionType() const { - LLWearableType::EType type = LLWearableType::WT_NONE; + selection_info_t result = std::make_pair(LLWearableType::WT_NONE, 0); if (mAddWearablesPanel != NULL && mAddWearablesPanel->getVisible()) { @@ -695,9 +870,11 @@ LLWearableType::EType LLPanelOutfitEdit::getAddMorePanelSelectionType() const { std::set<LLUUID> selected_uuids = mInventoryItemsPanel->getRootFolder()->getSelectionList(); - if (selected_uuids.size() == 1) + result.second = selected_uuids.size(); + + if (result.second == 1) { - type = getWearableTypeByItemUUID(*(selected_uuids.begin())); + result.first = getWearableTypeByItemUUID(*(selected_uuids.begin())); } } else if (mWearableItemsList != NULL && mWearableItemsList->getVisible()) @@ -705,14 +882,16 @@ LLWearableType::EType LLPanelOutfitEdit::getAddMorePanelSelectionType() const std::vector<LLUUID> selected_uuids; mWearableItemsList->getSelectedUUIDs(selected_uuids); - if (selected_uuids.size() == 1) + result.second = selected_uuids.size(); + + if (result.second == 1) { - type = getWearableTypeByItemUUID(selected_uuids.front()); + result.first = getWearableTypeByItemUUID(selected_uuids.front()); } } } - return type; + return result; } LLWearableType::EType LLPanelOutfitEdit::getWearableTypeByItemUUID(const LLUUID& item_uuid) const @@ -749,7 +928,7 @@ void LLPanelOutfitEdit::updatePlusButton() } // If any of the selected items are not wearable (due to already being worn OR being of the wrong type), disable the add button. - uuid_vec_t::iterator unwearable_item = std::find_if(selected_items.begin(), selected_items.end(), !boost::bind(& get_can_item_be_worn, _1)); + uuid_vec_t::iterator unwearable_item = std::find_if(selected_items.begin(), selected_items.end(), !boost::bind(&get_can_item_be_worn, _1)); bool can_add = ( unwearable_item == selected_items.end() ); mPlusBtn->setEnabled(can_add); @@ -809,15 +988,38 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) bool more_than_one_selected = ids.size() > 1; bool is_dummy_item = (ids.size() && dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem())); - //selected and expanded accordion tabs determine filtering when no item is selected + // selected, expanded accordion tabs and selection in flat list view determine filtering when no item is selected in COF + // selection in flat list view participates in determining filtering because of EXT-7963 + // So the priority of criterions in is: + // 1. Selected accordion tab | IF (any accordion selected) + // | filter_type = selected_accordion_type + // 2. Selected item in flat list view | ELSEIF (any item in flat list view selected) + // | filter_type = selected_item_type + // 3. Expanded accordion tab | ELSEIF (any accordion expanded) + // | filter_type = expanded accordion_type if (nothing_selected) { showWearablesListView(); - //selected accordion tab is more priority than expanded tab when determining filtering + //selected accordion tab is more priority than expanded tab + //and selected item in flat list view of 'Add more' panel when + //determining filtering LLAssetType::EType type = mCOFWearables->getSelectedAccordionAssetType(); if (type == LLAssetType::AT_NONE) + { //no accordion selected + + // when no accordion selected then selected item from flat list view + // has more priority than expanded when determining filtering + LLUUID selected_item_id = mWearableItemsList->getSelectedUUID(); + LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id); + if(item) { + showFilteredWearablesListView(item->getWearableType()); + return; + } + + // when no accordion selected and no selected items in flat list view + // determine filtering according to expanded accordion type = mCOFWearables->getExpandedAccordionAssetType(); } @@ -974,7 +1176,7 @@ void LLPanelOutfitEdit::updateVerbs() bool has_baseoutfit = LLAppearanceMgr::getInstance()->getBaseOutfitUUID().notNull(); mSaveComboBtn->setSaveBtnEnabled(!outfit_locked && outfit_is_dirty); - childSetEnabled(REVERT_BTN, outfit_is_dirty && has_baseoutfit); + getChildView(REVERT_BTN)->setEnabled(outfit_is_dirty && has_baseoutfit); mSaveComboBtn->setMenuItemEnabled("save_outfit", !outfit_locked && outfit_is_dirty); @@ -1011,13 +1213,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(); + } - S32 menu_y = mGearMenu->getRect().getHeight() + clicked_button->getRect().getHeight(); - LLMenuGL::showPopup(clicked_button, mGearMenu, 0, menu_y); + menu = mGearMenu; + } + + if (!menu) return; + + 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() @@ -1099,11 +1321,67 @@ void LLPanelOutfitEdit::getSelectedItemsUUID(uuid_vec_t& uuid_list) void LLPanelOutfitEdit::onCOFChanged() { - //the panel is only updated when is visible to a user - if (!isInVisibleChain()) return; - update(); } +void LLPanelOutfitEdit::updateWearablesPanelVerbButtons() +{ + if(mWearablesListViewPanel->getVisible()) + { + mFolderViewBtn->setToggleState(FALSE); + mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign()); + mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign()); + } + else if(mInventoryItemsPanel->getVisible()) + { + mListViewBtn->setToggleState(FALSE); + mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign()); + mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign()); + } +} + +void LLPanelOutfitEdit::saveListSelection() +{ + if(mWearablesListViewPanel->getVisible()) + { + std::set<LLUUID> selected_ids = mInventoryItemsPanel->getRootFolder()->getSelectionList(); + + 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); + } + mWearableItemsList->scrollToShowFirstSelectedItem(); + } + else if(mInventoryItemsPanel->getVisible()) + { + std::vector<LLUUID> selected_ids; + mWearableItemsList->getSelectedUUIDs(selected_ids); + + if(!selected_ids.size()) return; + + mInventoryItemsPanel->clearSelection(); + LLFolderView* root = mInventoryItemsPanel->getRootFolder(); + + if(!root) return; + + for(std::vector<LLUUID>::const_iterator item_id = selected_ids.begin(); item_id != selected_ids.end(); ++item_id) + { + LLFolderViewItem* item = root->getItemByID(*item_id); + if (!item) continue; + + LLFolderViewFolder* parent = item->getParentFolder(); + if(parent) + { + parent->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + mInventoryItemsPanel->getRootFolder()->changeSelection(item, TRUE); + } + mInventoryItemsPanel->getRootFolder()->scrollToShowSelection(); + } +} // EOF |