diff options
| -rwxr-xr-x | indra/llui/llfocusmgr.cpp | 1 | ||||
| -rwxr-xr-x | indra/llui/lllayoutstack.cpp | 2 | ||||
| -rwxr-xr-x | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/lloutfitgallery.cpp | 797 | ||||
| -rw-r--r-- | indra/newview/lloutfitgallery.h | 177 | ||||
| -rwxr-xr-x | indra/newview/lloutfitslist.cpp | 1234 | ||||
| -rwxr-xr-x | indra/newview/lloutfitslist.h | 204 | ||||
| -rwxr-xr-x | indra/newview/llpaneloutfitsinventory.cpp | 6 | ||||
| -rwxr-xr-x | indra/newview/llpaneloutfitsinventory.h | 4 | ||||
| -rwxr-xr-x | indra/newview/lltexturectrl.cpp | 2 | ||||
| -rwxr-xr-x | indra/newview/skins/default/colors.xml | 9 | ||||
| -rwxr-xr-x | indra/newview/skins/default/textures/textures.xml | 1 | ||||
| -rwxr-xr-x | indra/newview/skins/default/xui/en/floater_snapshot.xml | 4 | ||||
| -rwxr-xr-x | indra/newview/skins/default/xui/en/menu_outfit_gear.xml | 16 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/panel_outfit_gallery.xml | 115 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml | 71 | ||||
| -rwxr-xr-x | indra/newview/skins/default/xui/en/panel_outfits_inventory.xml | 11 | 
17 files changed, 2163 insertions, 493 deletions
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 1a51b96fdf..1b213c3418 100755 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -186,7 +186,6 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )  	LLUI::removePopup(view);  } -  void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only)  {  	// notes if keyboard focus is changed again (by onFocusLost/onFocusReceived) diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 69246a2f57..11769760aa 100755 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -283,7 +283,7 @@ void LLLayoutStack::removeChild(LLView* view)  	if (embedded_panelp)  	{  		mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp)); -		delete embedded_panelp; +		//delete embedded_panelp;  		updateFractionalSizes();  		mNeedsLayout = true;  	} diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 05483c4608..6567654a9d 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -412,6 +412,7 @@ set(viewer_SOURCE_FILES      llnotificationscripthandler.cpp      llnotificationstorage.cpp      llnotificationtiphandler.cpp +    lloutfitgallery.cpp      lloutfitslist.cpp      lloutfitobserver.cpp      lloutputmonitorctrl.cpp @@ -1024,6 +1025,7 @@ set(viewer_HEADER_FILES      llnotificationlistview.h      llnotificationmanager.h      llnotificationstorage.h +    lloutfitgallery.h      lloutfitslist.h      lloutfitobserver.h      lloutputmonitorctrl.h diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp new file mode 100644 index 0000000000..92827a7b6f --- /dev/null +++ b/indra/newview/lloutfitgallery.cpp @@ -0,0 +1,797 @@ +/**  + * @file lloutfitgallery.cpp + * @author Pavlo Kryvych + * @brief Visual gallery of agent's outfits for My Appearance side panel + * + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2015, Linden Research, Inc. + *  + * 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. + *  + * 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. + *  + * 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$ + */ + +#include "llviewerprecompiledheaders.h" // must be first include +#include "lloutfitgallery.h" + +#include <boost/foreach.hpp> + +// llcommon +#include "llcommonutils.h" +#include "llvfile.h" + +#include "llappearancemgr.h" +#include "lleconomy.h" +#include "llerror.h" +#include "llfilepicker.h" +#include "llfloaterperms.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "lllocalbitmaps.h" +#include "llviewermenufile.h" +#include "llwearableitemslist.h" + + +static LLPanelInjector<LLOutfitGallery> t_outfit_gallery("outfit_gallery"); +static LLOutfitGallery* gOutfitGallery = NULL; + +LLOutfitGallery::LLOutfitGallery() +    : LLOutfitListBase(), +      mTexturesObserver(NULL), +      mScrollPanel(NULL), +      mGalleryPanel(NULL), +      galleryCreated(false), +      mRowCount(0), +      mItemsAddedCount(0) +{ +} + +BOOL LLOutfitGallery::postBuild() +{ +    BOOL rv = LLOutfitListBase::postBuild(); +    mScrollPanel = getChild<LLScrollContainer>("gallery_scroll_panel"); +    mGalleryPanel = getChild<LLPanel>("gallery_panel"); +    return rv; +} + +void LLOutfitGallery::onOpen(const LLSD& info) +{ +    LLOutfitListBase::onOpen(info); +    if (!galleryCreated) +    { +        loadPhotos(); +        uuid_vec_t cats; +        getCurrentCategories(cats); +        int n = cats.size(); +        buildGalleryPanel(n); +        mScrollPanel->addChild(mGalleryPanel); +        for (int i = 0; i < n; i++) +        { +            addToGallery(mOutfitMap[cats[i]]); +        } +        galleryCreated = true; +    } +} + +#define LAYOUT_STACK_HEIGHT 180 +#define GALLERY_VERTICAL_GAP 10 +#define GALLERY_HORIZONTAL_GAP 10 +#define GALLERY_ITEM_WIDTH 150 +#define GALLERY_ITEM_HEIGHT 175 +#define GALLERY_ITEM_HGAP 16  +#define ITEMS_IN_ROW 3 +#define LAYOUT_STACK_WIDTH 166 * ITEMS_IN_ROW//498 +#define GALLERY_WIDTH 163 * ITEMS_IN_ROW//485//290 + +LLPanel* LLOutfitGallery::addLastRow() +{ +    mRowCount++; +    int row = 0; +    int vgap = GALLERY_VERTICAL_GAP * row; +    LLPanel* result = buildLayoutStak(0, row * LAYOUT_STACK_HEIGHT + vgap); +    mGalleryPanel->addChild(result); +    return result; +} + +void LLOutfitGallery::moveRowUp(int row) +{ +    moveRow(row, mRowCount - 1 - row + 1); +} + +void LLOutfitGallery::moveRowDown(int row) +{ +    moveRow(row, mRowCount - 1 - row - 1); +} + +void LLOutfitGallery::moveRow(int row, int pos) +{ +    int vgap = GALLERY_VERTICAL_GAP * pos; +    moveLayoutStak(mStacks[row], 0, pos * LAYOUT_STACK_HEIGHT + vgap); +} + +void LLOutfitGallery::removeLastRow() +{ +    mRowCount--; +    mGalleryPanel->removeChild(mLastRowStack); +    mStacks.pop_back(); +    mLastRowStack = mStacks.back(); +} + +LLPanel* LLOutfitGallery::addToRow(LLPanel* row_stack, LLOutfitGalleryItem* item, int pos, int hgap) +{ +    LLPanel* lpanel = buildLayoutPanel(pos * GALLERY_ITEM_WIDTH + hgap); +    lpanel->addChild(item); +    row_stack->addChild(lpanel); +    mPanels.push_back(lpanel); +    return lpanel; +} + +void LLOutfitGallery::addToGallery(LLOutfitGalleryItem* item) +{ +    mItemsAddedCount++; +    mItemIndexMap[item] = mItemsAddedCount - 1; +    int n = mItemsAddedCount; +    int row_count = (n % ITEMS_IN_ROW) == 0 ? n / ITEMS_IN_ROW : n / ITEMS_IN_ROW + 1; +    int n_prev = n - 1; +    int row_count_prev = (n_prev % ITEMS_IN_ROW) == 0 ? n_prev / ITEMS_IN_ROW : n_prev / ITEMS_IN_ROW + 1; + +    bool add_row = row_count != row_count_prev; +    int pos = 0; +    if (add_row) +    { +        for (int i = 0; i < row_count_prev; i++) +        { +            moveRowUp(i); +        } +        mLastRowStack = addLastRow(); +        mStacks.push_back(mLastRowStack); +    } +    pos = (n - 1) % ITEMS_IN_ROW; +    mItems.push_back(item); +    addToRow(mLastRowStack, item, pos, GALLERY_HORIZONTAL_GAP * pos); +    reshapeGalleryPanel(row_count); +} + + +void LLOutfitGallery::removeFromGalleryLast(LLOutfitGalleryItem* item) +{ +    int n_prev = mItemsAddedCount; +    int n = mItemsAddedCount - 1; +    int row_count = (n % ITEMS_IN_ROW) == 0 ? n / ITEMS_IN_ROW : n / ITEMS_IN_ROW + 1; +    int row_count_prev = (n_prev % ITEMS_IN_ROW) == 0 ? n_prev / ITEMS_IN_ROW : n_prev / ITEMS_IN_ROW + 1; +    mItemsAddedCount--; + +    bool remove_row = row_count != row_count_prev; +    //int pos = (n_prev - 1) % ITEMS_IN_ROW; +    removeFromLastRow(mItems[mItemsAddedCount]); +    mItems.pop_back(); +    if (remove_row) +    { +        for (int i = 0; i < row_count_prev - 1; i++) +        { +            moveRowDown(i); +        } +        removeLastRow(); +    } +    reshapeGalleryPanel(row_count); +} + + +void LLOutfitGallery::removeFromGalleryMiddle(LLOutfitGalleryItem* item) +{ +    int n = mItemIndexMap[item]; +    mItemIndexMap.erase(item); +    std::vector<LLOutfitGalleryItem*> saved; +    for (int i = mItemsAddedCount - 1; i > n; i--) +    { +        saved.push_back(mItems[i]); +        removeFromGalleryLast(mItems[i]); +    } +    removeFromGalleryLast(mItems[n]); +    int saved_count = saved.size(); +    for (int i = 0; i < saved_count; i++) +    { +        addToGallery(saved.back()); +        saved.pop_back(); +    } +} + +void LLOutfitGallery::removeFromLastRow(LLOutfitGalleryItem* item) +{ +    mPanels.back()->removeChild(item); +    mLastRowStack->removeChild(mPanels.back()); +    mPanels.pop_back(); +} + +LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name) +{ +    LLOutfitGalleryItem::Params giparams; +    LLOutfitGalleryItem* gitem = LLUICtrlFactory::create<LLOutfitGalleryItem>(giparams); +    LLRect girect = LLRect(0, GALLERY_ITEM_HEIGHT - GALLERY_ITEM_HEIGHT, +        GALLERY_ITEM_WIDTH, 0); +    //gitem->setRect(girect); +    gitem->reshape(GALLERY_ITEM_WIDTH, GALLERY_ITEM_HEIGHT); +    gitem->setVisible(true); +    gitem->setFollowsLeft(); +    gitem->setFollowsTop(); +    gitem->setOutfitName(name); +    return gitem; +} + +void LLOutfitGallery::buildGalleryPanel(int row_count) +{ +    LLPanel::Params params; +    mGalleryPanel = LLUICtrlFactory::create<LLPanel>(params); +    reshapeGalleryPanel(row_count); +} + +void LLOutfitGallery::reshapeGalleryPanel(int row_count) +{ +    int bottom = 0; +    int left = 0; +    int height = row_count * (LAYOUT_STACK_HEIGHT + GALLERY_VERTICAL_GAP); +    LLRect rect = LLRect(left, bottom + height, left + GALLERY_WIDTH, bottom); +    mGalleryPanel->setRect(rect); +    mGalleryPanel->reshape(GALLERY_WIDTH, height); +    mGalleryPanel->setVisible(true); +    mGalleryPanel->setFollowsLeft(); +    mGalleryPanel->setFollowsTop(); +} + +LLPanel* LLOutfitGallery::buildLayoutPanel(int left) +{ +    LLPanel::Params lpparams; +    int top = 0; +    LLPanel* lpanel = LLUICtrlFactory::create<LLPanel>(lpparams); +    LLRect rect = LLRect(left, top + GALLERY_ITEM_HEIGHT, left + GALLERY_ITEM_WIDTH + GALLERY_ITEM_HGAP, top); +    lpanel->setRect(rect); +    lpanel->reshape(GALLERY_ITEM_WIDTH + GALLERY_ITEM_HGAP, GALLERY_ITEM_HEIGHT); +    lpanel->setVisible(true); +    lpanel->setFollowsLeft(); +    lpanel->setFollowsTop(); +    return lpanel; +} + +LLPanel* LLOutfitGallery::buildLayoutStak(int left, int bottom) +{ +    LLPanel::Params sparams; +    LLPanel* stack = LLUICtrlFactory::create<LLPanel>(sparams); +    moveLayoutStak(stack, left, bottom); +    return stack; +} + +void LLOutfitGallery::moveLayoutStak(LLPanel* stack, int left, int bottom) +{ +    LLRect rect = LLRect(left, bottom + LAYOUT_STACK_HEIGHT, left + LAYOUT_STACK_WIDTH, bottom); +    stack->setRect(rect); +    stack->reshape(LAYOUT_STACK_WIDTH, LAYOUT_STACK_HEIGHT); +    stack->setVisible(true); +    stack->setFollowsLeft(); +    stack->setFollowsTop(); +} + +LLOutfitGallery::~LLOutfitGallery() +{ +    if (gInventory.containsObserver(mTexturesObserver)) +    { +        gInventory.removeObserver(mTexturesObserver); +    } +    delete mTexturesObserver; +} + +void LLOutfitGallery::setFilterSubString(const std::string& string) +{ +    //TODO: Implement filtering + +    sFilterSubString = string; +} + +void LLOutfitGallery::onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id) +{ +    if (mOutfitMap[base_id]) +    { +        mOutfitMap[base_id]->setOutfitWorn(true); +    } +    if (mOutfitMap[prev_id]) +    { +        mOutfitMap[prev_id]->setOutfitWorn(false); +    } +} + +void LLOutfitGallery::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) +{ +} + +void LLOutfitGallery::getCurrentCategories(uuid_vec_t& vcur) +{ +    for (outfit_map_t::const_iterator iter = mOutfitMap.begin(); +        iter != mOutfitMap.end(); +        iter++) +    { +        if ((*iter).second != NULL) +        { +            vcur.push_back((*iter).first); +        } +    } +} + +void LLOutfitGallery::updateAddedCategory(LLUUID cat_id) +{ +    LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); +    if (!cat) return; + +    std::string name = cat->getName(); +    LLOutfitGalleryItem* item = buildGalleryItem(name); +    mOutfitMap.insert(LLOutfitGallery::outfit_map_value_t(cat_id, item)); +    item->setRightMouseDownCallback(boost::bind(&LLOutfitListBase::outfitRightClickCallBack, this, +        _1, _2, _3, cat_id)); +    LLWearableItemsList* list = NULL; +    item->setFocusReceivedCallback(boost::bind(&LLOutfitListBase::ñhangeOutfitSelection, this, list, cat_id)); +    if (galleryCreated) +    { +        addToGallery(item); +    } +} + +void LLOutfitGallery::updateRemovedCategory(LLUUID cat_id) +{ +    outfit_map_t::iterator outfits_iter = mOutfitMap.find(cat_id); +    if (outfits_iter != mOutfitMap.end()) +    { +        //const LLUUID& outfit_id = outfits_iter->first; +        LLOutfitGalleryItem* item = outfits_iter->second; + +        // An outfit is removed from the list. Do the following: +        // 2. Remove the outfit from selection. +        //deselectOutfit(outfit_id); + +        // 3. Remove category UUID to accordion tab mapping. +        mOutfitMap.erase(outfits_iter); + +        // 4. Remove outfit from gallery. +        removeFromGalleryMiddle(item); + +        // kill removed item +        if (item != NULL) +        { +            item->die(); +        } +    } + +} + +void LLOutfitGallery::updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name) +{ +    outfit_map_t::iterator outfit_iter = mOutfitMap.find(cat->getUUID()); +    if (outfit_iter != mOutfitMap.end()) +    { +        // Update name of outfit in gallery +        LLOutfitGalleryItem* item = outfit_iter->second; +        if (item) +        { +            item->setOutfitName(name); +        } +    } +} + +void LLOutfitGallery::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) +{ +    if (mOutfitMenu && cat_id.notNull()) +    { +        uuid_vec_t selected_uuids; +        selected_uuids.push_back(cat_id); +        mOutfitMenu->show(ctrl, selected_uuids, x, y); +    } +} + +void LLOutfitGallery::onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) +{ +    if (mSelectedOutfitUUID == category_id) +        return; +    if (mOutfitMap[mSelectedOutfitUUID]) +    { +        mOutfitMap[mSelectedOutfitUUID]->setSelected(FALSE); +    } +    if (mOutfitMap[category_id]) +    { +        mOutfitMap[category_id]->setSelected(TRUE); +    } +} + +bool LLOutfitGallery::hasItemSelected() +{ +    return false; +} + +bool LLOutfitGallery::canWearSelected() +{ +    return false; +} + +LLOutfitListGearMenuBase* LLOutfitGallery::createGearMenu() +{ +    return new LLOutfitGalleryGearMenu(this); +} + +static LLDefaultChildRegistry::Register<LLOutfitGalleryItem> r("outfit_gallery_item"); + +LLOutfitGalleryItem::LLOutfitGalleryItem(const Params& p) +    : LLPanel(p), +    mTexturep(NULL), +    mSelected(false), +    mWorn(false) +{ +    buildFromFile("panel_outfit_gallery_item.xml"); +} + +LLOutfitGalleryItem::~LLOutfitGalleryItem() +{ + +} + +BOOL LLOutfitGalleryItem::postBuild() +{ +    setDefaultImage(); + +    mOutfitNameText = getChild<LLTextBox>("outfit_name"); +    mOutfitWornText = getChild<LLTextBox>("outfit_worn_text"); +    mFotoBgPanel = getChild<LLPanel>("foto_bg_panel"); +    mTextBgPanel = getChild<LLPanel>("text_bg_panel"); +    setOutfitWorn(false); +    return TRUE; +} + +void LLOutfitGalleryItem::draw() +{ +    LLPanel::draw(); + +     +    // Draw border +    LLUIColor border_color = LLUIColorTable::instance().getColor(mSelected ? "OutfitGalleryItemSelected" : "OutfitGalleryItemUnselected", LLColor4::white); +    LLRect border = getChildView("preview_outfit")->getRect(); +    border.mRight = border.mRight + 1; +    gl_rect_2d(border, border_color.get(), FALSE); + +    // If the floater is focused, don't apply its alpha to the texture (STORM-677). +    const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); +    if (mTexturep) +    { +        //if (mTexturep->getComponents() == 4) +        //{ +        //    gl_rect_2d_checkerboard(interior, alpha); +        //} + +        // Interior +        LLRect interior = border; +        interior.stretch(-1); + +        gl_draw_scaled_image(interior.mLeft - 1, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha); + +        // Pump the priority +        mTexturep->addTextureStats((F32)(interior.getWidth() * interior.getHeight())); +    } +     +} + +void LLOutfitGalleryItem::setOutfitName(std::string name) +{ +    mOutfitNameText->setText(name); +} + +void LLOutfitGalleryItem::setOutfitWorn(bool value) +{ +    mWorn = value; +    //LLStringUtil::format_map_t string_args; +    //std::string worn_text = getString("worn_text", string_args); +    LLStringUtil::format_map_t worn_string_args; +    std::string worn_string = getString("worn_string", worn_string_args); +    LLUIColor text_color = LLUIColorTable::instance().getColor(mSelected ? "White" : (mWorn ? "OutfitGalleryItemWorn" : "White"), LLColor4::white); +    mOutfitWornText->setReadOnlyColor(text_color.get()); +    mOutfitNameText->setReadOnlyColor(text_color.get()); +    mOutfitWornText->setValue(value ? worn_string : ""); +} + +void LLOutfitGalleryItem::setSelected(bool value) +{ +    mSelected = value; +    mTextBgPanel->setBackgroundVisible(value); +    setOutfitWorn(mWorn); +} + +BOOL LLOutfitGalleryItem::handleMouseDown(S32 x, S32 y, MASK mask) +{ +    setFocus(TRUE); +    return LLUICtrl::handleMouseDown(x, y, mask); +} + +void LLOutfitGalleryItem::setImageAssetId(LLUUID image_asset_id) +{ +    mTexturep = LLViewerTextureManager::getFetchedTexture(image_asset_id); +    mTexturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW); +} + +void LLOutfitGalleryItem::setDefaultImage() +{ +    /* +    LLUUID imageAssetID("e417f443-a199-bac1-86b0-0530e177fb54"); +    mTexturep = LLViewerTextureManager::getFetchedTexture(imageAssetID); +    mTexturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW); +    */ +    mTexturep = NULL; +} + +LLOutfitGalleryGearMenu::LLOutfitGalleryGearMenu(LLOutfitListBase* olist) +    : LLOutfitListGearMenuBase(olist) +{ +} + +void LLOutfitGalleryGearMenu::onUpdateItemsVisibility() +{ +    if (!mMenu) return; +    mMenu->setItemVisible("expand", FALSE); +    mMenu->setItemVisible("collapse", FALSE); +    mMenu->setItemVisible("upload_foto", TRUE); +    mMenu->setItemVisible("load_assets", TRUE); +    LLOutfitListGearMenuBase::onUpdateItemsVisibility(); +} + +void LLOutfitGalleryGearMenu::onUploadFoto() +{ +    LLUUID selected_outfit_id = getSelectedOutfitID(); +    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList); +    if (gallery && selected_outfit_id.notNull()) +    { +        gallery->uploadPhoto(selected_outfit_id); +    } +    if (selected_outfit_id.notNull()) +    { + +    } +} + +void LLOutfitGalleryGearMenu::onLoadAssets() +{ +    LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList); +    if (gallery != NULL) +    { +        gallery->loadPhotos(); +    } +} + +void LLOutfitGallery::loadPhotos() +{ +    //Iterate over inventory +    LLUUID textures = gInventory.findCategoryUUIDForType(LLFolderType::EType::FT_TEXTURE); +    LLViewerInventoryCategory* category = gInventory.getCategory(textures); +    if (!category) +        return; + +    if (mTexturesObserver == NULL) +    { +        mTexturesObserver = new LLInventoryCategoriesObserver(); +        gInventory.addObserver(mTexturesObserver); +    } + +    // Start observing changes in "My Outfits" category. +    mTexturesObserver->addCategory(textures, +        boost::bind(&LLOutfitGallery::refreshTextures, this, textures)); + +    category->fetch(); +    refreshTextures(textures); +} + +void LLOutfitGallery::refreshTextures(const LLUUID& category_id) +{ +    LLInventoryModel::cat_array_t cat_array; +    LLInventoryModel::item_array_t item_array; + +    // Collect all sub-categories of a given category. +    LLIsType is_texture(LLAssetType::AT_TEXTURE); +    gInventory.collectDescendentsIf( +        category_id, +        cat_array, +        item_array, +        LLInventoryModel::EXCLUDE_TRASH, +        is_texture); + +    //Find textures which contain outfit UUID string in description +    LLInventoryModel::item_array_t uploaded_item_array; +    BOOST_FOREACH(LLViewerInventoryItem* item, item_array) +    { +        std::string desc = item->getDescription(); + +        LLUUID outfit_id(desc); + +        //Check whether description contains correct UUID of outfit +        if (outfit_id.isNull()) +            continue; + +        outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id); +        if (outfit_it != mOutfitMap.end() && !outfit_it->first.isNull()) +        { +            uploaded_item_array.push_back(item); +        } +    } + +    uuid_vec_t vadded; +    uuid_vec_t vremoved; + +    // Create added and removed items vectors. +    computeDifferenceOfTextures(uploaded_item_array, vadded, vremoved); + +    BOOST_FOREACH(LLUUID item_id, vadded) +    { +        LLViewerInventoryItem* added_item = gInventory.getItem(item_id); +        LLUUID asset_id = added_item->getAssetUUID(); +        std::string desc = added_item->getDescription(); +        LLUUID outfit_id(desc); +        mOutfitMap[outfit_id]->setImageAssetId(asset_id); +        mTextureMap[outfit_id] = added_item; +    } + +    BOOST_FOREACH(LLUUID item_id, vremoved) +    { +        LLViewerInventoryItem* rm_item = gInventory.getItem(item_id); +        std::string desc = rm_item->getDescription(); +        LLUUID outfit_id(desc); +        mOutfitMap[outfit_id]->setDefaultImage(); +        mTextureMap.erase(outfit_id); +    } + +    /* +    LLInventoryModel::item_array_t::const_iterator it = item_array.begin(); +    for ( ; it != item_array.end(); it++) +    { +        LLViewerInventoryItem* item = (*it); +        LLUUID asset_id = item->getAssetUUID(); + +        std::string desc = item->getDescription(); + +        LLUUID outfit_id(desc); + +        //Check whether description contains correct UUID of outfit +        if (outfit_id.isNull()) +            continue; + +        outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id); +        if (outfit_it != mOutfitMap.end() && !outfit_it->first.isNull()) +        { +            outfit_it->second->setImageAssetId(asset_id); +            mTextureMap[outfit_id] = item; +        } + +         +        //LLUUID* item_idp = new LLUUID(); + +        //gOutfitGallery = this; +        //const BOOL high_priority = TRUE; +        //gAssetStorage->getAssetData(asset_id, +        //    LLAssetType::AT_TEXTURE, +        //    onLoadComplete, +        //    (void**)item_idp, +        //    high_priority); +        // +        ////mAssetStatus = PREVIEW_ASSET_LOADING; +         +    } +    */ +} + +void LLOutfitGallery::onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) +{ +    LL_WARNS() << "asset_uuid: " << asset_uuid.asString() << LL_ENDL; + +    LLUUID* outfit_id = (LLUUID*)user_data; +        if (!user_data) +        return; +    LL_WARNS() << "outfit_id: " << outfit_id->asString() << LL_ENDL; + +    outfit_map_t::iterator it = gOutfitGallery->mOutfitMap.find(*outfit_id); +    if (it != gOutfitGallery->mOutfitMap.end() && !it->first.isNull()) +    { +    } +} + +void LLOutfitGallery::uploadPhoto(LLUUID outfit_id) +{ +    outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id); +    if (outfit_it == mOutfitMap.end() || outfit_it->first.isNull()) +    { +        return; +    } + +    bool add_successful = false; +    LLFilePicker& picker = LLFilePicker::instance(); +    if (picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE)) +    { +        std::string filename = picker.getFirstFile(); +        LLLocalBitmap* unit = new LLLocalBitmap(filename); +        if (unit->getValid()) +        { +            add_successful = true; +            LLAssetStorage::LLStoreAssetCallback callback = NULL; +            S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); // kinda hack - assumes that unsubclassed LLFloaterNameDesc is only used for uploading chargeable assets, which it is right now (it's only used unsubclassed for the sound upload dialog, and THAT should be a subclass). +            void *nruserdata = NULL; +            nruserdata = (void *)&outfit_id; + +            LL_WARNS() << "selected_outfit_id: " << outfit_id.asString() << LL_ENDL; + +            //LLViewerInventoryItem *outfit = gInventory.getItem(selected_outfit_id); +            LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(outfit_id); +            if (!outfit_cat) return; + +            checkRemovePhoto(outfit_id); + +            LLStringUtil::format_map_t foto_string_args; +            foto_string_args["OUTFIT_NAME"] = outfit_cat->getName(); +            std::string display_name = getString("outfit_foto_string", foto_string_args); + +            upload_new_resource(filename, // file +                display_name, +                outfit_id.asString(), +                0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, +                LLFloaterPerms::getNextOwnerPerms("Uploads"), +                LLFloaterPerms::getGroupPerms("Uploads"), +                LLFloaterPerms::getEveryonePerms("Uploads"), +                display_name, callback, expected_upload_cost, nruserdata); +        } +    } +} + +bool LLOutfitGallery::checkRemovePhoto(LLUUID outfit_id) +{ +    //remove existing photo of outfit from inventory +    texture_map_t::iterator texture_it = mTextureMap.find(outfit_id); +    if (texture_it != mTextureMap.end()) { +        gInventory.removeItem(texture_it->second->getUUID()); +        return true; +    } +    return false; +} + +void LLOutfitGallery::setUploadedPhoto(LLUUID outfit_id, LLUUID asset_id) +{ + +} + +void LLOutfitGallery::computeDifferenceOfTextures( +    const LLInventoryModel::item_array_t& vtextures, +    uuid_vec_t& vadded, +    uuid_vec_t& vremoved) +{ +    uuid_vec_t vnew; +    // Creating a vector of newly collected sub-categories UUIDs. +    for (LLInventoryModel::item_array_t::const_iterator iter = vtextures.begin(); +        iter != vtextures.end(); +        iter++) +    { +        vnew.push_back((*iter)->getUUID()); +    } + +    uuid_vec_t vcur; +    // Creating a vector of currently uploaded texture UUIDs. +    for (texture_map_t::const_iterator iter = mTextureMap.begin(); +        iter != mTextureMap.end(); +        iter++) +    { +        vcur.push_back((*iter).second->getUUID()); +    } +//    getCurrentCategories(vcur); + +    LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved); + +} diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h new file mode 100644 index 0000000000..01d56d917f --- /dev/null +++ b/indra/newview/lloutfitgallery.h @@ -0,0 +1,177 @@ +/**  + * @file lloutfitgallery.h + * @author Pavlo Kryvych + * @brief Visual gallery of agent's outfits for My Appearance side panel + * + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2015, Linden Research, Inc. + *  + * 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. + *  + * 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. + *  + * 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$ + */ + +#ifndef LL_LLOUTFITGALLERYCTRL_H +#define LL_LLOUTFITGALLERYCTRL_H + +#include "llextendedstatus.h" +#include "lliconctrl.h" +#include "lllayoutstack.h" +#include "lloutfitslist.h" +#include "llpanelappearancetab.h" +#include "llviewertexture.h" + +#include <vector> + +class LLVFS; +class LLOutfitGalleryItem; +class LLOutfitListGearMenuBase; +class LLOutfitGalleryGearMenu; + +class LLOutfitGallery : public LLOutfitListBase +{ +public: +    friend class LLOutfitGalleryGearMenu; +    LLOutfitGallery(); +    virtual ~LLOutfitGallery(); + +    /*virtual*/ BOOL postBuild(); +    /*virtual*/ void onOpen(const LLSD& info); + +    /*virtual*/ void setFilterSubString(const std::string& string); + +    /*virtual*/ void getCurrentCategories(uuid_vec_t& vcur); +    /*virtual*/ void updateAddedCategory(LLUUID cat_id); +    /*virtual*/ void updateRemovedCategory(LLUUID cat_id); +    /*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name); + +    /*virtual*/ bool hasItemSelected(); +    /*virtual*/ bool canWearSelected(); + +    /*virtual*/ bool getHasExpandableFolders() { return FALSE; } + +    void refreshTextures(const LLUUID& category_id); +    void computeDifferenceOfTextures(const LLInventoryModel::item_array_t& vtextures, uuid_vec_t& vadded, uuid_vec_t& vremoved); + +protected: +    /*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id); +    /*virtual*/ void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid); +    /*virtual*/ void onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id); +    /*virtual*/ void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id); + +    /*virtual*/ void onCollapseAllFolders() {} +    /*virtual*/ void onExpandAllFolders() {} +    /*virtual*/ LLOutfitListGearMenuBase* createGearMenu(); + +private: +    void loadPhotos(); +    void uploadPhoto(LLUUID outfit_id); +    bool checkRemovePhoto(LLUUID outfit_id); +    void setUploadedPhoto(LLUUID outfit_id, LLUUID asset_id); +    void addToGallery(LLOutfitGalleryItem* item); +    void removeFromGalleryLast(LLOutfitGalleryItem* item); +    void removeFromGalleryMiddle(LLOutfitGalleryItem* item); +    LLPanel* addLastRow(); +    void removeLastRow(); +    void moveRowUp(int row); +    void moveRowDown(int row); +    void moveRow(int row, int pos); +    LLPanel* addToRow(LLPanel* row_stack, LLOutfitGalleryItem* item, int pos, int hgap); +    void removeFromLastRow(LLOutfitGalleryItem* item); + +    static void onLoadComplete(LLVFS *vfs, +        const LLUUID& asset_uuid, +        LLAssetType::EType type, +        void* user_data, S32 status, LLExtStat ext_status); + +    LLOutfitGalleryItem* buildGalleryItem(std::string name); +    void buildGalleryPanel(int row_count); +    void reshapeGalleryPanel(int row_count); +    LLPanel* buildLayoutPanel(int left); +    LLPanel* buildLayoutStak(int left, int bottom); +    void moveLayoutStak(LLPanel* stack, int left, int bottom); +    LLView* mView; +    std::vector<LLPanel*> mStacks; +    std::vector<LLPanel*> mPanels; +    std::vector<LLOutfitGalleryItem*> mItems; +    LLScrollContainer* mScrollPanel; +    LLPanel* mGalleryPanel; +    LLPanel* mLastRowStack; +    bool galleryCreated; +    int mRowCount; +    int mItemsAddedCount; + +    typedef std::map<LLUUID, LLOutfitGalleryItem*>      outfit_map_t; +    typedef outfit_map_t::value_type                    outfit_map_value_t; +    outfit_map_t                                        mOutfitMap; +    typedef std::map<LLUUID, LLViewerInventoryItem*>    texture_map_t; +    typedef texture_map_t::value_type                   texture_map_value_t; +    texture_map_t                                       mTextureMap; +    typedef std::map<LLOutfitGalleryItem*, int>         item_num_map_t; +    typedef item_num_map_t::value_type                  item_numb_map_value_t; +    item_num_map_t                                      mItemIndexMap; + + +    LLInventoryCategoriesObserver* 	mTexturesObserver; + +}; + +//static LLOutfitGallery* gOutfitGallery; + +class LLOutfitGalleryGearMenu : public LLOutfitListGearMenuBase +{ +public: +    friend class LLOutfitGallery; +    LLOutfitGalleryGearMenu(LLOutfitListBase* olist); + +protected: +    /*virtual*/ void onUpdateItemsVisibility(); + +private: +    /*virtual*/ void onUploadFoto(); +    /*virtual*/ void onLoadAssets(); +}; + +class LLOutfitGalleryItem : public LLPanel +{ +public: +    struct Params : public LLInitParam::Block<Params, LLPanel::Params> +    {}; + +    LLOutfitGalleryItem(const Params& p); +    virtual ~LLOutfitGalleryItem(); + +    /*virtual*/ BOOL postBuild(); +    /*virtual*/ void draw(); +    /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + +    void setDefaultImage(); +    void setImageAssetId(LLUUID asset_id); +    void setOutfitName(std::string name); +    void setOutfitWorn(bool value); +    void setSelected(bool value); +private: +    LLPointer<LLViewerTexture> mTexturep; +    LLTextBox* mOutfitNameText; +    LLTextBox* mOutfitWornText; +    LLPanel* mTextBgPanel; +    LLPanel* mFotoBgPanel; +    bool     mSelected; +    bool     mWorn; +}; + +#endif  // LL_LLOUTFITGALLERYCTRL_H diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 883221382c..736da5d411 100755 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -38,7 +38,7 @@  #include "llfloatersidepanelcontainer.h"  #include "llinventoryfunctions.h"  #include "llinventorymodel.h" -#include "lllistcontextmenu.h" +//#include "lllistcontextmenu.h"  #include "llmenubutton.h"  #include "llnotificationsutil.h"  #include "lloutfitobserver.h" @@ -98,339 +98,204 @@ const outfit_accordion_tab_params& get_accordion_tab_params()  } -////////////////////////////////////////////////////////////////////////// +static LLPanelInjector<LLOutfitsList> t_outfits_list("outfits_list"); -class LLOutfitListGearMenu +LLOutfitsList::LLOutfitsList() +    :   LLOutfitListBase() +    ,   mAccordion(NULL) +	,	mListCommands(NULL) +	,	mItemSelected(false)  { -public: -	LLOutfitListGearMenu(LLOutfitsList* olist) -	:	mOutfitList(olist), -		mMenu(NULL) -	{ -		llassert_always(mOutfitList); +//	mCategoriesObserver = new LLInventoryCategoriesObserver(); -		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(&LLOutfitsList::removeSelected, mOutfitList)); -		registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenu::onCreate, this, _2)); -		registrar.add("Gear.Collapse", boost::bind(&LLOutfitsList::collapse_all_folders, mOutfitList)); -		registrar.add("Gear.Expand", boost::bind(&LLOutfitsList::expand_all_folders, mOutfitList)); - -		registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenu::onAdd, this)); - -		enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenu::onEnable, this, _2)); -		enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenu::onVisible, this, _2)); - -		mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>( -			"menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -		llassert(mMenu); -	} - -	void updateItemsVisibility() -	{ -		if (!mMenu) return; +//	mGearMenu = new LLOutfitListGearMenu(this); +} -		bool have_selection = getSelectedOutfitID().notNull(); -		mMenu->setItemVisible("sepatator1", have_selection); -		mMenu->setItemVisible("sepatator2", have_selection); -		mMenu->arrangeAndClear(); // update menu height -	} +LLOutfitsList::~LLOutfitsList() +{ +//	delete mGearMenu; +} -	LLToggleableMenu* getMenu() { return mMenu; } +BOOL LLOutfitsList::postBuild() +{ +	mAccordion = getChild<LLAccordionCtrl>("outfits_accordion"); +	mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR); -private: -	const LLUUID& getSelectedOutfitID() -	{ -		return mOutfitList->getSelectedOutfitUUID(); -	} +	//LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn"); -	LLViewerInventoryCategory* getSelectedOutfit() -	{ -		const LLUUID& selected_outfit_id = getSelectedOutfitID(); -		if (selected_outfit_id.isNull()) -		{ -			return NULL; -		} +	//menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenu::updateItemsVisibility, mGearMenu)); +	//menu_gear_btn->setMenu(mGearMenu->getMenu()); -		LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id); -		return cat; -	} +    return LLOutfitListBase::postBuild(); +} -	void onWear() -	{ -		LLViewerInventoryCategory* selected_outfit = getSelectedOutfit(); -		if (selected_outfit) -		{ -			LLAppearanceMgr::instance().wearInventoryCategory( -				selected_outfit, /*copy=*/ FALSE, /*append=*/ FALSE); -		} -	} +//virtual +void LLOutfitsList::onOpen(const LLSD& info) +{ +    if (!mIsInitialized) +    { +        const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); +        // Start observing changes in Current Outfit category. +        mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this)); +    } -	void onAdd() -	{ -		const LLUUID& selected_id = getSelectedOutfitID(); +    LLOutfitListBase::onOpen(info); -		if (selected_id.notNull()) -		{ -			LLAppearanceMgr::getInstance()->addCategoryToCurrentOutfit(selected_id); -		} -	} + //   if (!mIsInitialized) +	//{ +	//	// *TODO: I'm not sure is this check necessary but it never match while developing. +	//	if (!gInventory.isInventoryUsable()) +	//		return; -	void onTakeOff() -	{ -		// Take off selected outfit. -			const LLUUID& selected_outfit_id = getSelectedOutfitID(); -			if (selected_outfit_id.notNull()) -			{ -				LLAppearanceMgr::instance().takeOffOutfit(selected_outfit_id); -			} -		} +	//	const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	void onRename() -	{ -		const LLUUID& selected_outfit_id = getSelectedOutfitID(); -		if (selected_outfit_id.notNull()) -		{ -			LLAppearanceMgr::instance().renameOutfit(selected_outfit_id); -		} -	} +	//	// *TODO: I'm not sure is this check necessary but it never match while developing. +	//	LLViewerInventoryCategory* category = gInventory.getCategory(outfits); +	//	if (!category) +	//		return; -	void onCreate(const LLSD& data) -	{ -		LLWearableType::EType type = LLWearableType::typeNameToType(data.asString()); -		if (type == LLWearableType::WT_NONE) -		{ -			LL_WARNS() << "Invalid wearable type" << LL_ENDL; -			return; -		} +	//	gInventory.addObserver(mCategoriesObserver); -		LLAgentWearables::createWearable(type, true); -	} +	//	// Start observing changes in "My Outfits" category. +	//	mCategoriesObserver->addCategory(outfits, +	//		boost::bind(&LLOutfitsList::refreshList, this, outfits)); -	bool onEnable(LLSD::String param) -	{ -		// Handle the "Wear - Replace Current Outfit" menu option specially -		// because LLOutfitList::isActionEnabled() checks whether it's allowed -		// to wear selected outfit OR selected items, while we're only -		// interested in the outfit (STORM-183). -		if ("wear" == param) -		{ -			return LLAppearanceMgr::instance().getCanReplaceCOF(mOutfitList->getSelectedOutfitUUID()); -		} +	//	const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); -		return mOutfitList->isActionEnabled(param); -	} +	//	// Start observing changes in Current Outfit category. +	//	mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this)); -	bool onVisible(LLSD::String param) -	{ -		const LLUUID& selected_outfit_id = getSelectedOutfitID(); -		if (selected_outfit_id.isNull()) // no selection or invalid outfit selected -		{ -			return false; -		} +	//	LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this)); +	//	LLOutfitObserver::instance().addBOFReplacedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this)); -		// *TODO This condition leads to menu item behavior inconsistent with -		// "Wear" button behavior and should be modified or removed. -		bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id; +	//	// Fetch "My Outfits" contents and refresh the list to display +	//	// initially fetched items. If not all items are fetched now +	//	// the observer will refresh the list as soon as the new items +	//	// arrive. +	//	category->fetch(); +	//	refreshList(outfits); +	//	highlightBaseOutfit(); -		if ("wear" == param) -		{ -			return !is_worn; -		} +	//	mIsInitialized = true; +	//} -		return true; -	} +	LLAccordionCtrlTab* selected_tab = mAccordion->getSelectedTab(); +	if (!selected_tab) return; -	LLOutfitsList*			mOutfitList; -	LLToggleableMenu*		mMenu; -}; +	// Pass focus to the selected outfit tab. +	selected_tab->showAndFocusHeader(); +} -////////////////////////////////////////////////////////////////////////// -class LLOutfitContextMenu : public LLListContextMenu +void LLOutfitsList::updateAddedCategory(LLUUID cat_id)  { -public: - -	LLOutfitContextMenu(LLOutfitsList* outfit_list) -	:		LLListContextMenu(), -	 		mOutfitList(outfit_list) -	{} -protected: -	/* virtual */ LLContextMenu* createMenu() -	{ -		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; -		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; -		LLUUID selected_id = mUUIDs.front(); - -		registrar.add("Outfit.WearReplace", -			boost::bind(&LLAppearanceMgr::replaceCurrentOutfit, &LLAppearanceMgr::instance(), selected_id)); -		registrar.add("Outfit.WearAdd", -			boost::bind(&LLAppearanceMgr::addCategoryToCurrentOutfit, &LLAppearanceMgr::instance(), selected_id)); -		registrar.add("Outfit.TakeOff", -				boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id)); -		registrar.add("Outfit.Edit", boost::bind(editOutfit)); -		registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id)); -		registrar.add("Outfit.Delete", boost::bind(&LLOutfitsList::removeSelected, mOutfitList)); - -		enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2)); -		enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitContextMenu::onVisible, this, _2)); - -		return createFromFile("menu_outfit_tab.xml"); -	} +    LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); +    if (!cat) return; -	bool onEnable(LLSD::String param) -	{ -		LLUUID outfit_cat_id = mUUIDs.back(); +    std::string name = cat->getName(); -		if ("rename" == param) -		{ -			return get_is_category_renameable(&gInventory, outfit_cat_id); -		} -		else if ("wear_replace" == param) -		{ -			return LLAppearanceMgr::instance().getCanReplaceCOF(outfit_cat_id); -		} -		else if ("wear_add" == param) -		{ -			return LLAppearanceMgr::getCanAddToCOF(outfit_cat_id); -		} -		else if ("take_off" == param) -		{ -			return LLAppearanceMgr::getCanRemoveFromCOF(outfit_cat_id); -		} +    outfit_accordion_tab_params tab_params(get_accordion_tab_params()); +    LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params); +    if (!tab) return; +    LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list); +    wearable_list->setShape(tab->getLocalRect()); +    tab->addChild(wearable_list); -		return true; -	} +    tab->setName(name); +    tab->setTitle(name); -	bool onVisible(LLSD::String param) -	{ -		LLUUID outfit_cat_id = mUUIDs.back(); -		bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == outfit_cat_id; +    // *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated. +    tab->setDisplayChildren(false); +    mAccordion->addCollapsibleCtrl(tab); -		if ("edit" == param) -		{ -			return is_worn; -		} -		else if ("wear_replace" == param) -		{ -			return !is_worn; -		} -		else if ("delete" == param) -		{ -			return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id); -		} +    // Start observing the new outfit category. +    LLWearableItemsList* list = tab->getChild<LLWearableItemsList>("wearable_items_list"); +    if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id))) +    { +        // Remove accordion tab if category could not be added to observer. +        mAccordion->removeCollapsibleCtrl(tab); -		return true; -	} +        // kill removed tab +        tab->die(); +        return; +    } -	static void editOutfit() -	{ -		LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); -	} +    // Map the new tab with outfit category UUID. +    mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab)); -	static void renameOutfit(const LLUUID& outfit_cat_id) -	{ -		LLAppearanceMgr::instance().renameOutfit(outfit_cat_id); -	} +    tab->setRightMouseDownCallback(boost::bind(&LLOutfitListBase::outfitRightClickCallBack, this, +        _1, _2, _3, cat_id)); -private: -	LLOutfitsList*	mOutfitList; -}; +    // Setting tab focus callback to monitor currently selected outfit. +    tab->setFocusReceivedCallback(boost::bind(&LLOutfitListBase::ñhangeOutfitSelection, this, list, cat_id)); -////////////////////////////////////////////////////////////////////////// +    // Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875) +    tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id)); -static LLPanelInjector<LLOutfitsList> t_outfits_list("outfits_list"); +    // force showing list items that don't match current filter(EXT-7158) +    list->setForceShowingUnmatchedItems(true); -LLOutfitsList::LLOutfitsList() -	:	LLPanelAppearanceTab() -	,	mAccordion(NULL) -	,	mListCommands(NULL) -	,	mIsInitialized(false) -	,	mItemSelected(false) -{ -	mCategoriesObserver = new LLInventoryCategoriesObserver(); +    // Setting list commit callback to monitor currently selected wearable item. +    list->setCommitCallback(boost::bind(&LLOutfitsList::onListSelectionChange, this, _1)); -	mGearMenu = new LLOutfitListGearMenu(this); -	mOutfitMenu = new LLOutfitContextMenu(this); -} +    // Setting list refresh callback to apply filter on list change. +    list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1)); -LLOutfitsList::~LLOutfitsList() -{ -	delete mGearMenu; -	delete mOutfitMenu; +    list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3)); -	if (gInventory.containsObserver(mCategoriesObserver)) -	{ -		gInventory.removeObserver(mCategoriesObserver); -	} -	delete mCategoriesObserver; -} +    // Fetch the new outfit contents. +    cat->fetch(); -BOOL LLOutfitsList::postBuild() -{ -	mAccordion = getChild<LLAccordionCtrl>("outfits_accordion"); -	mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR); +    // Refresh the list of outfit items after fetch(). +    // Further list updates will be triggered by the category observer. +    list->updateList(cat_id); -	LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn"); +    // If filter is currently applied we store the initial tab state and +    // open it to show matched items if any. +    if (!sFilterSubString.empty()) +    { +        tab->notifyChildren(LLSD().with("action", "store_state")); +        tab->setDisplayChildren(true); -	menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenu::updateItemsVisibility, mGearMenu)); -	menu_gear_btn->setMenu(mGearMenu->getMenu()); +        // Setting mForceRefresh flag will make the list refresh its contents +        // even if it is not currently visible. This is required to apply the +        // filter to the newly added list. +        list->setForceRefresh(true); -	return TRUE; +        list->setFilterSubString(sFilterSubString); +    }  } -//virtual -void LLOutfitsList::onOpen(const LLSD& /*info*/) +void LLOutfitsList::updateRemovedCategory(LLUUID cat_id)  { -	if (!mIsInitialized) -	{ -		// *TODO: I'm not sure is this check necessary but it never match while developing. -		if (!gInventory.isInventoryUsable()) -			return; - -		const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - -		// *TODO: I'm not sure is this check necessary but it never match while developing. -		LLViewerInventoryCategory* category = gInventory.getCategory(outfits); -		if (!category) -			return; - -		gInventory.addObserver(mCategoriesObserver); - -		// Start observing changes in "My Outfits" category. -		mCategoriesObserver->addCategory(outfits, -			boost::bind(&LLOutfitsList::refreshList, this, outfits)); - -		const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - -		// Start observing changes in Current Outfit category. -		mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this)); - -		LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this)); -		LLOutfitObserver::instance().addBOFReplacedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this)); - -		// Fetch "My Outfits" contents and refresh the list to display -		// initially fetched items. If not all items are fetched now -		// the observer will refresh the list as soon as the new items -		// arrive. -		category->fetch(); -		refreshList(outfits); -		highlightBaseOutfit(); - -		mIsInitialized = true; -	} - -	LLAccordionCtrlTab* selected_tab = mAccordion->getSelectedTab(); -	if (!selected_tab) return; - -	// Pass focus to the selected outfit tab. -	selected_tab->showAndFocusHeader(); +    outfits_map_t::iterator outfits_iter = mOutfitsMap.find(cat_id); +    if (outfits_iter != mOutfitsMap.end()) +    { +    	const LLUUID& outfit_id = outfits_iter->first; +    	LLAccordionCtrlTab* tab = outfits_iter->second; + +    	// An outfit is removed from the list. Do the following: +    	// 1. Remove outfit category from observer to stop monitoring its changes. +    	mCategoriesObserver->removeCategory(outfit_id); + +    	// 2. Remove the outfit from selection. +    	deselectOutfit(outfit_id); + +    	// 3. Remove category UUID to accordion tab mapping. +    	mOutfitsMap.erase(outfits_iter); + +    	// 4. Remove outfit tab from accordion. +    	mAccordion->removeCollapsibleCtrl(tab); + +    	// kill removed tab +    	if (tab != NULL) +    	{ +    		tab->die(); +    	} +    }  } +/*  void LLOutfitsList::refreshList(const LLUUID& category_id)  {  	LLInventoryModel::cat_array_t cat_array; @@ -457,111 +322,114 @@ void LLOutfitsList::refreshList(const LLUUID& category_id)  		 ++iter)  	{  		const LLUUID cat_id = (*iter); -		LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); -		if (!cat) continue; +        updateAddedCategory(cat_id); +		//LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); +		//if (!cat) continue; -		std::string name = cat->getName(); +		//std::string name = cat->getName(); -		outfit_accordion_tab_params tab_params(get_accordion_tab_params()); -		LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params); -		if (!tab) continue; -		LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list); -		wearable_list->setShape(tab->getLocalRect()); -		tab->addChild(wearable_list); +		//outfit_accordion_tab_params tab_params(get_accordion_tab_params()); +		//LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params); +		//if (!tab) continue; +		//LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list); +		//wearable_list->setShape(tab->getLocalRect()); +		//tab->addChild(wearable_list); -		tab->setName(name); -		tab->setTitle(name); +		//tab->setName(name); +		//tab->setTitle(name); -		// *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated. -		tab->setDisplayChildren(false); -		mAccordion->addCollapsibleCtrl(tab); +		//// *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated. +		//tab->setDisplayChildren(false); +		//mAccordion->addCollapsibleCtrl(tab); -		// Start observing the new outfit category. -		LLWearableItemsList* list  = tab->getChild<LLWearableItemsList>("wearable_items_list"); -		if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id))) -		{ -			// Remove accordion tab if category could not be added to observer. -			mAccordion->removeCollapsibleCtrl(tab); +		//// Start observing the new outfit category. +		//LLWearableItemsList* list  = tab->getChild<LLWearableItemsList>("wearable_items_list"); +		//if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id))) +		//{ +		//	// Remove accordion tab if category could not be added to observer. +		//	mAccordion->removeCollapsibleCtrl(tab); -			// kill removed tab -				tab->die(); -			continue; -		} +		//	// kill removed tab +		//		tab->die(); +		//	continue; +		//} -		// Map the new tab with outfit category UUID. -		mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab)); +		//// Map the new tab with outfit category UUID. +		//mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab)); -		tab->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onAccordionTabRightClick, this, -			_1, _2, _3, cat_id)); +		//tab->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onAccordionTabRightClick, this, +		//	_1, _2, _3, cat_id)); -		// Setting tab focus callback to monitor currently selected outfit. -		tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id)); +		//// Setting tab focus callback to monitor currently selected outfit. +		//tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id)); -		// Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875) -		tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id)); +		//// Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875) +		//tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id)); -		// force showing list items that don't match current filter(EXT-7158) -		list->setForceShowingUnmatchedItems(true); +		//// force showing list items that don't match current filter(EXT-7158) +		//list->setForceShowingUnmatchedItems(true); -		// Setting list commit callback to monitor currently selected wearable item. -		list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1)); +		//// Setting list commit callback to monitor currently selected wearable item. +		//list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1)); -		// Setting list refresh callback to apply filter on list change. -		list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1)); +		//// Setting list refresh callback to apply filter on list change. +		//list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1)); -		list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3)); +		//list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3)); -		// Fetch the new outfit contents. -		cat->fetch(); +		//// Fetch the new outfit contents. +		//cat->fetch(); -		// Refresh the list of outfit items after fetch(). -		// Further list updates will be triggered by the category observer. -		list->updateList(cat_id); +		//// Refresh the list of outfit items after fetch(). +		//// Further list updates will be triggered by the category observer. +		//list->updateList(cat_id); -		// If filter is currently applied we store the initial tab state and -		// open it to show matched items if any. -		if (!sFilterSubString.empty()) -		{ -			tab->notifyChildren(LLSD().with("action","store_state")); -			tab->setDisplayChildren(true); +		//// If filter is currently applied we store the initial tab state and +		//// open it to show matched items if any. +		//if (!sFilterSubString.empty()) +		//{ +		//	tab->notifyChildren(LLSD().with("action","store_state")); +		//	tab->setDisplayChildren(true); -			// Setting mForceRefresh flag will make the list refresh its contents -			// even if it is not currently visible. This is required to apply the -			// filter to the newly added list. -			list->setForceRefresh(true); +		//	// Setting mForceRefresh flag will make the list refresh its contents +		//	// even if it is not currently visible. This is required to apply the +		//	// filter to the newly added list. +		//	list->setForceRefresh(true); -			list->setFilterSubString(sFilterSubString); -		} +		//	list->setFilterSubString(sFilterSubString); +		//}  	}  	// Handle removed tabs.  	for (uuid_vec_t::const_iterator iter=vremoved.begin(); iter != vremoved.end(); ++iter)  	{ -		outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter)); -		if (outfits_iter != mOutfitsMap.end()) -		{ -			const LLUUID& outfit_id = outfits_iter->first; -			LLAccordionCtrlTab* tab = outfits_iter->second; - -			// An outfit is removed from the list. Do the following: -			// 1. Remove outfit category from observer to stop monitoring its changes. -			mCategoriesObserver->removeCategory(outfit_id); - -			// 2. Remove the outfit from selection. -			deselectOutfit(outfit_id); - -			// 3. Remove category UUID to accordion tab mapping. -			mOutfitsMap.erase(outfits_iter); - -			// 4. Remove outfit tab from accordion. -			mAccordion->removeCollapsibleCtrl(tab); - -			// kill removed tab -			if (tab != NULL) -			{ -				tab->die(); -			} -		} +        const LLUUID cat_id = (*iter); +        updateRemovedCategory(cat_id); +        //outfits_map_t::iterator outfits_iter = mOutfitsMap.find(cat_id); +		//if (outfits_iter != mOutfitsMap.end()) +		//{ +		//	const LLUUID& outfit_id = outfits_iter->first; +		//	LLAccordionCtrlTab* tab = outfits_iter->second; + +		//	// An outfit is removed from the list. Do the following: +		//	// 1. Remove outfit category from observer to stop monitoring its changes. +		//	mCategoriesObserver->removeCategory(outfit_id); + +		//	// 2. Remove the outfit from selection. +		//	deselectOutfit(outfit_id); + +		//	// 3. Remove category UUID to accordion tab mapping. +		//	mOutfitsMap.erase(outfits_iter); + +		//	// 4. Remove outfit tab from accordion. +		//	mAccordion->removeCollapsibleCtrl(tab); + +		//	// kill removed tab +		//	if (tab != NULL) +		//	{ +		//		tab->die(); +		//	} +		//}  	}  	// Get changed items from inventory model and update outfit tabs @@ -571,34 +439,29 @@ void LLOutfitsList::refreshList(const LLUUID& category_id)  		 items_iter != changed_items.end();  		 ++items_iter)  	{ -		updateOutfitTab(*items_iter); +		updateChangedCategoryName(*items_iter);  	}  	mAccordion->sort();  } +*/ -void LLOutfitsList::highlightBaseOutfit() +//virtual +void LLOutfitsList::onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id)  { -	// id of base outfit -	LLUUID base_id = LLAppearanceMgr::getInstance()->getBaseOutfitUUID(); -	if (base_id != mHighlightedOutfitUUID) -	{ -		if (mOutfitsMap[mHighlightedOutfitUUID]) -		{ -			mOutfitsMap[mHighlightedOutfitUUID]->setTitleFontStyle("NORMAL"); -			mOutfitsMap[mHighlightedOutfitUUID]->setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor")); -		} - -		mHighlightedOutfitUUID = base_id; -	} -	if (mOutfitsMap[base_id]) +    if (mOutfitsMap[prev_id]) +    { +        mOutfitsMap[prev_id]->setTitleFontStyle("NORMAL"); +        mOutfitsMap[prev_id]->setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor")); +    } +    if (mOutfitsMap[base_id])  	{  		mOutfitsMap[base_id]->setTitleFontStyle("BOLD");  		mOutfitsMap[base_id]->setTitleColor(LLUIColorTable::instance().getColor("SelectedOutfitTextColor"));  	}  } -void LLOutfitsList::onSelectionChange(LLUICtrl* ctrl) +void LLOutfitsList::onListSelectionChange(LLUICtrl* ctrl)  {  	LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl);  	if (!list) return; @@ -606,10 +469,10 @@ void LLOutfitsList::onSelectionChange(LLUICtrl* ctrl)  	LLViewerInventoryItem *item = gInventory.getItem(list->getSelectedUUID());  	if (!item) return; -	changeOutfitSelection(list, item->getParentUUID()); +	ñhangeOutfitSelection(list, item->getParentUUID());  } -void LLOutfitsList::performAction(std::string action) +void LLOutfitListBase::performAction(std::string action)  {  	if (mSelectedOutfitUUID.isNull()) return; @@ -630,23 +493,7 @@ void LLOutfitsList::performAction(std::string action)  	}  } -void LLOutfitsList::removeSelected() -{ -	LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLOutfitsList::onOutfitsRemovalConfirmation, this, _1, _2)); -} - -void LLOutfitsList::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if (option != 0) return; // canceled - -	if (mSelectedOutfitUUID.notNull()) -	{ -		gInventory.removeCategory(mSelectedOutfitUUID); -	} -} - -void LLOutfitsList::setSelectedOutfitByUUID(const LLUUID& outfit_uuid) +void LLOutfitsList::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid)  {  	for (outfits_map_t::iterator iter = mOutfitsMap.begin();  			iter != mOutfitsMap.end(); @@ -661,7 +508,7 @@ void LLOutfitsList::setSelectedOutfitByUUID(const LLUUID& outfit_uuid)  			if (!list) continue;  			tab->setFocus(TRUE); -			changeOutfitSelection(list, outfit_uuid); +			ñhangeOutfitSelection(list, outfit_uuid);  			tab->setDisplayChildren(true);  		} @@ -677,14 +524,14 @@ void LLOutfitsList::setFilterSubString(const std::string& string)  }  // virtual -bool LLOutfitsList::isActionEnabled(const LLSD& userdata) +bool LLOutfitListBase::isActionEnabled(const LLSD& userdata)  {  	if (mSelectedOutfitUUID.isNull()) return false;  	const std::string command_name = userdata.asString();  	if (command_name == "delete")  	{ -		return !mItemSelected && LLAppearanceMgr::instance().getCanRemoveOutfit(mSelectedOutfitUUID); +        return !hasItemSelected() && LLAppearanceMgr::instance().getCanRemoveOutfit(mSelectedOutfitUUID);  	}  	if (command_name == "rename")  	{ @@ -745,7 +592,7 @@ void LLOutfitsList::getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const  	}  } -void LLOutfitsList::collapse_all_folders() +void LLOutfitsList::onCollapseAllFolders()  {  	for (outfits_map_t::iterator iter = mOutfitsMap.begin();  			iter != mOutfitsMap.end(); @@ -759,7 +606,7 @@ void LLOutfitsList::collapse_all_folders()  	}  } -void LLOutfitsList::expand_all_folders() +void LLOutfitsList::onExpandAllFolders()  {  	for (outfits_map_t::iterator iter = mOutfitsMap.begin();  			iter != mOutfitsMap.end(); @@ -773,11 +620,6 @@ void LLOutfitsList::expand_all_folders()  	}  } -boost::signals2::connection LLOutfitsList::setSelectionChangeCallback(selection_change_callback_t cb) -{ -	return mSelectionChangeSignal.connect(cb); -} -  bool LLOutfitsList::hasItemSelected()  {  	return mItemSelected; @@ -786,6 +628,7 @@ bool LLOutfitsList::hasItemSelected()  //////////////////////////////////////////////////////////////////////////  // Private methods  ////////////////////////////////////////////////////////////////////////// +/*  void LLOutfitsList::computeDifference(  	const LLInventoryModel::cat_array_t& vcats,   	uuid_vec_t& vadded,  @@ -811,17 +654,13 @@ void LLOutfitsList::computeDifference(  	LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);  } +*/ -void LLOutfitsList::updateOutfitTab(const LLUUID& category_id) +void LLOutfitsList::updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name)  { -	outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id); +    outfits_map_t::iterator outfits_iter = mOutfitsMap.find(cat->getUUID());  	if (outfits_iter != mOutfitsMap.end())  	{ -		LLViewerInventoryCategory *cat = gInventory.getCategory(category_id); -		if (!cat) return; - -		std::string name = cat->getName(); -  		// Update tab name with the new category name.  		LLAccordionCtrlTab* tab = outfits_iter->second;  		if (tab) @@ -836,10 +675,10 @@ void LLOutfitsList::resetItemSelection(LLWearableItemsList* list, const LLUUID&  {  	list->resetSelection();  	mItemSelected = false; -	setSelectedOutfitUUID(category_id); +	signalSelectionOutfitUUID(category_id);  } -void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) +void LLOutfitsList::onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id)  {  	MASK mask = gKeyboard->currentMask(TRUE); @@ -865,12 +704,6 @@ void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUI  	mItemSelected = list && (list->getSelectedItem() != NULL);  	mSelectedListsMap.insert(wearables_lists_map_value_t(category_id, list)); -	setSelectedOutfitUUID(category_id); -} - -void LLOutfitsList::setSelectedOutfitUUID(const LLUUID& category_id) -{ -	mSelectionChangeSignal(mSelectedOutfitUUID = category_id);  }  void LLOutfitsList::deselectOutfit(const LLUUID& category_id) @@ -881,7 +714,7 @@ void LLOutfitsList::deselectOutfit(const LLUUID& category_id)  	// Reset selection if the outfit is selected.  	if (category_id == mSelectedOutfitUUID)  	{ -		setSelectedOutfitUUID(LLUUID::null); +		signalSelectionOutfitUUID(LLUUID::null);  	}  } @@ -890,7 +723,7 @@ void LLOutfitsList::restoreOutfitSelection(LLAccordionCtrlTab* tab, const LLUUID  	// Try restoring outfit selection after filtering.  	if (mAccordion->getSelectedTab() == tab)  	{ -		setSelectedOutfitUUID(category_id); +		signalSelectionOutfitUUID(category_id);  	}  } @@ -1036,24 +869,6 @@ bool LLOutfitsList::canWearSelected()  	return true;  } -void LLOutfitsList::onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) -{ -	LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl); -	if(mOutfitMenu && is_tab_header_clicked(tab, y) && cat_id.notNull()) -	{ -		// Focus tab header to trigger tab selection change. -		LLUICtrl* header = tab->findChild<LLUICtrl>("dd_header"); -		if (header) -		{ -			header->setFocus(TRUE); -		} - -		uuid_vec_t selected_uuids; -		selected_uuids.push_back(cat_id); -		mOutfitMenu->show(ctrl, selected_uuids, x, y); -	} -} -  void LLOutfitsList::wearSelectedItems()  {  	uuid_vec_t selected_uuids; @@ -1132,6 +947,47 @@ void LLOutfitsList::onCOFChanged()  	}  } +void LLOutfitsList::getCurrentCategories(uuid_vec_t& vcur) +{ +    // Creating a vector of currently displayed sub-categories UUIDs. +    for (outfits_map_t::const_iterator iter = mOutfitsMap.begin(); +        iter != mOutfitsMap.end(); +        iter++) +    { +        vcur.push_back((*iter).first); +    } +} + + +void LLOutfitsList::sortOutfits() +{ +    mAccordion->sort(); +} + +void LLOutfitsList::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) +{ +    LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl); +    if (mOutfitMenu && is_tab_header_clicked(tab, y) && cat_id.notNull()) +    { +        // Focus tab header to trigger tab selection change. +        LLUICtrl* header = tab->findChild<LLUICtrl>("dd_header"); +        if (header) +        { +            header->setFocus(TRUE); +        } + +        uuid_vec_t selected_uuids; +        selected_uuids.push_back(cat_id); +        mOutfitMenu->show(ctrl, selected_uuids, x, y); +    } +} + +LLOutfitListGearMenuBase* LLOutfitsList::createGearMenu() +{ +    return new LLOutfitListGearMenu(this); +} + +  bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y)  {  	if(!tab || !tab->getHeaderVisible()) return false; @@ -1140,4 +996,490 @@ bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y)  	return y >= header_bottom;  } +LLOutfitListBase::LLOutfitListBase() +    :   LLPanelAppearanceTab() +    ,   mIsInitialized(false) +{ +    mCategoriesObserver = new LLInventoryCategoriesObserver(); +    mOutfitMenu = new LLOutfitContextMenu(this); +    //mGearMenu = createGearMenu(); +} + +LLOutfitListBase::~LLOutfitListBase() +{ +    delete mOutfitMenu; +    delete mGearMenu; + +    if (gInventory.containsObserver(mCategoriesObserver)) +    { +        gInventory.removeObserver(mCategoriesObserver); +    } +    delete mCategoriesObserver; +} + +void LLOutfitListBase::onOpen(const LLSD& info) +{ +    if (!mIsInitialized) +    { +        // *TODO: I'm not sure is this check necessary but it never match while developing. +        if (!gInventory.isInventoryUsable()) +            return; + +        const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + +        // *TODO: I'm not sure is this check necessary but it never match while developing. +        LLViewerInventoryCategory* category = gInventory.getCategory(outfits); +        if (!category) +            return; + +        gInventory.addObserver(mCategoriesObserver); + +        // Start observing changes in "My Outfits" category. +        mCategoriesObserver->addCategory(outfits, +            boost::bind(&LLOutfitListBase::refreshList, this, outfits)); + +        const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + +        // Start observing changes in Current Outfit category. +        //mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this)); + +        LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(&LLOutfitListBase::highlightBaseOutfit, this)); +        LLOutfitObserver::instance().addBOFReplacedCallback(boost::bind(&LLOutfitListBase::highlightBaseOutfit, this)); + +        // Fetch "My Outfits" contents and refresh the list to display +        // initially fetched items. If not all items are fetched now +        // the observer will refresh the list as soon as the new items +        // arrive. +        category->fetch(); +        refreshList(outfits); +        highlightBaseOutfit(); + +        mIsInitialized = true; +    } + +    //LLAccordionCtrlTab* selected_tab = mAccordion->getSelectedTab(); +    //if (!selected_tab) return; + +    //// Pass focus to the selected outfit tab. +    //selected_tab->showAndFocusHeader(); +} + +void LLOutfitListBase::refreshList(const LLUUID& category_id) +{ +    LLInventoryModel::cat_array_t cat_array; +    LLInventoryModel::item_array_t item_array; + +    // Collect all sub-categories of a given category. +    LLIsType is_category(LLAssetType::AT_CATEGORY); +    gInventory.collectDescendentsIf( +        category_id, +        cat_array, +        item_array, +        LLInventoryModel::EXCLUDE_TRASH, +        is_category); + +    uuid_vec_t vadded; +    uuid_vec_t vremoved; + +    // Create added and removed items vectors. +    computeDifference(cat_array, vadded, vremoved); + +    // Handle added tabs. +    for (uuid_vec_t::const_iterator iter = vadded.begin(); +        iter != vadded.end(); +        ++iter) +    { +        const LLUUID cat_id = (*iter); +        updateAddedCategory(cat_id); +    } + +    // Handle removed tabs. +    for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter) +    { +        const LLUUID cat_id = (*iter); +        updateRemovedCategory(cat_id); +    } + +    // Get changed items from inventory model and update outfit tabs +    // which might have been renamed. +    const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs(); +    for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin(); +        items_iter != changed_items.end(); +        ++items_iter) +    { +        LLViewerInventoryCategory *cat = gInventory.getCategory(*items_iter); +        if (!cat) return; + +        std::string name = cat->getName(); + +        updateChangedCategoryName(cat, name); +    } + +    sortOutfits(); +} + +void LLOutfitListBase::computeDifference( +    const LLInventoryModel::cat_array_t& vcats, +    uuid_vec_t& vadded, +    uuid_vec_t& vremoved) +{ +    uuid_vec_t vnew; +    // Creating a vector of newly collected sub-categories UUIDs. +    for (LLInventoryModel::cat_array_t::const_iterator iter = vcats.begin(); +        iter != vcats.end(); +        iter++) +    { +        vnew.push_back((*iter)->getUUID()); +    } + +    uuid_vec_t vcur; +    //// Creating a vector of currently displayed sub-categories UUIDs. +    //for (outfits_map_t::const_iterator iter = mOutfitsMap.begin(); +    //    iter != mOutfitsMap.end(); +    //    iter++) +    //{ +    //    vcur.push_back((*iter).first); +    //} +    getCurrentCategories(vcur); + +    LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved); +} + +void LLOutfitListBase::sortOutfits() +{ +} + +void LLOutfitListBase::highlightBaseOutfit() +{ +    // id of base outfit +    LLUUID base_id = LLAppearanceMgr::getInstance()->getBaseOutfitUUID(); +    if (base_id != mHighlightedOutfitUUID) +    { +        LLUUID prev_id = mHighlightedOutfitUUID; +        mHighlightedOutfitUUID = base_id; +        onHighlightBaseOutfit(base_id, prev_id); +    } + +} + +void LLOutfitListBase::removeSelected() +{ +    LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLOutfitListBase::onOutfitsRemovalConfirmation, this, _1, _2)); +} + +void LLOutfitListBase::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response) +{ +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +    if (option != 0) return; // canceled + +    if (mSelectedOutfitUUID.notNull()) +    { +        gInventory.removeCategory(mSelectedOutfitUUID); +    } +} + +void LLOutfitListBase::setSelectedOutfitByUUID(const LLUUID& outfit_uuid) +{ +    onSetSelectedOutfitByUUID(outfit_uuid); +} + +boost::signals2::connection LLOutfitListBase::setSelectionChangeCallback(selection_change_callback_t cb) +{ +    return mSelectionChangeSignal.connect(cb); +} + +void LLOutfitListBase::signalSelectionOutfitUUID(const LLUUID& category_id) +{ +    mSelectionChangeSignal(category_id); +} + +void LLOutfitListBase::outfitRightClickCallBack(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) +{ +    onOutfitRightClick(ctrl, x, y, cat_id); +} + +void LLOutfitListBase::ñhangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) +{ +    onChangeOutfitSelection(list, category_id); +    mSelectedOutfitUUID = category_id; +    signalSelectionOutfitUUID(category_id); +} + +BOOL LLOutfitListBase::postBuild() +{ +    mGearMenu = createGearMenu(); + +    LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn"); + +    menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenuBase::updateItemsVisibility, mGearMenu)); +    menu_gear_btn->setMenu(mGearMenu->getMenu()); +    return TRUE; +} + +void LLOutfitListBase::collapseAllFolders() +{ +    onCollapseAllFolders(); +} + +void LLOutfitListBase::expandAllFolders() +{ +    onExpandAllFolders(); +} + +LLContextMenu* LLOutfitContextMenu::createMenu() +{ +    LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; +    LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; +    LLUUID selected_id = mUUIDs.front(); + +    registrar.add("Outfit.WearReplace", +        boost::bind(&LLAppearanceMgr::replaceCurrentOutfit, &LLAppearanceMgr::instance(), selected_id)); +    registrar.add("Outfit.WearAdd", +        boost::bind(&LLAppearanceMgr::addCategoryToCurrentOutfit, &LLAppearanceMgr::instance(), selected_id)); +    registrar.add("Outfit.TakeOff", +        boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id)); +    registrar.add("Outfit.Edit", boost::bind(editOutfit)); +    registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id)); +    registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList)); + +    enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2)); +    enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitContextMenu::onVisible, this, _2)); + +    return createFromFile("menu_outfit_tab.xml"); + +} + +bool LLOutfitContextMenu::onEnable(LLSD::String param) +{ +    LLUUID outfit_cat_id = mUUIDs.back(); + +    if ("rename" == param) +    { +        return get_is_category_renameable(&gInventory, outfit_cat_id); +    } +    else if ("wear_replace" == param) +    { +        return LLAppearanceMgr::instance().getCanReplaceCOF(outfit_cat_id); +    } +    else if ("wear_add" == param) +    { +        return LLAppearanceMgr::getCanAddToCOF(outfit_cat_id); +    } +    else if ("take_off" == param) +    { +        return LLAppearanceMgr::getCanRemoveFromCOF(outfit_cat_id); +    } + +    return true; +} + +bool LLOutfitContextMenu::onVisible(LLSD::String param) +{ +    LLUUID outfit_cat_id = mUUIDs.back(); +    bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == outfit_cat_id; + +    if ("edit" == param) +    { +        return is_worn; +    } +    else if ("wear_replace" == param) +    { +        return !is_worn; +    } +    else if ("delete" == param) +    { +        return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id); +    } + +    return true; +} + +//static +void LLOutfitContextMenu::editOutfit() +{ +    LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); +} + +void LLOutfitContextMenu::renameOutfit(const LLUUID& outfit_cat_id) +{ +    LLAppearanceMgr::instance().renameOutfit(outfit_cat_id); +} + +LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist) +    :   mOutfitList(olist), +        mMenu(NULL) +{ +    llassert_always(mOutfitList); + +    LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; +    LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + +    registrar.add("Gear.Wear", boost::bind(&LLOutfitListGearMenuBase::onWear, this)); +    registrar.add("Gear.TakeOff", boost::bind(&LLOutfitListGearMenuBase::onTakeOff, this)); +    registrar.add("Gear.Rename", boost::bind(&LLOutfitListGearMenuBase::onRename, this)); +    registrar.add("Gear.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList)); +    registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenuBase::onCreate, this, _2)); +    registrar.add("Gear.Collapse", boost::bind(&LLOutfitListBase::onCollapseAllFolders, mOutfitList)); +    registrar.add("Gear.Expand", boost::bind(&LLOutfitListBase::onExpandAllFolders, mOutfitList)); + +    registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this)); + +    registrar.add("Gear.UploadFoto", boost::bind(&LLOutfitListGearMenuBase::onUploadFoto, this)); +    registrar.add("Gear.LoadAssets", boost::bind(&LLOutfitListGearMenuBase::onLoadAssets, this)); +     +    enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenuBase::onEnable, this, _2)); +    enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenuBase::onVisible, this, _2)); + +    mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>( +        "menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +    llassert(mMenu); +} + +void LLOutfitListGearMenuBase::updateItemsVisibility() +{ +    onUpdateItemsVisibility(); +} + +void LLOutfitListGearMenuBase::onUpdateItemsVisibility() +{ +    if (!mMenu) return; + +    bool have_selection = getSelectedOutfitID().notNull(); +    mMenu->setItemVisible("sepatator1", have_selection); +    mMenu->setItemVisible("sepatator2", have_selection); +    //mMenu->setItemVisible("expand", mOutfitList->getHasExpandableFolders()); +    //mMenu->setItemVisible("collapse", mOutfitList->getHasExpandableFolders()); +    mMenu->arrangeAndClear(); // update menu height +} + +LLToggleableMenu* LLOutfitListGearMenuBase::getMenu() +{ +    return mMenu; +} +const LLUUID& LLOutfitListGearMenuBase::getSelectedOutfitID() +{ +    return mOutfitList->getSelectedOutfitUUID(); +} + +LLViewerInventoryCategory* LLOutfitListGearMenuBase::getSelectedOutfit() +{ +    const LLUUID& selected_outfit_id = getSelectedOutfitID(); +    if (selected_outfit_id.isNull()) +    { +        return NULL; +    } + +    LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id); +    return cat; +} + +void LLOutfitListGearMenuBase::onWear() +{ +    LLViewerInventoryCategory* selected_outfit = getSelectedOutfit(); +    if (selected_outfit) +    { +        LLAppearanceMgr::instance().wearInventoryCategory( +            selected_outfit, /*copy=*/ FALSE, /*append=*/ FALSE); +    } +} + +void LLOutfitListGearMenuBase::onAdd() +{ +    const LLUUID& selected_id = getSelectedOutfitID(); + +    if (selected_id.notNull()) +    { +        LLAppearanceMgr::getInstance()->addCategoryToCurrentOutfit(selected_id); +    } +} + +void LLOutfitListGearMenuBase::onTakeOff() +{ +    // Take off selected outfit. +    const LLUUID& selected_outfit_id = getSelectedOutfitID(); +    if (selected_outfit_id.notNull()) +    { +        LLAppearanceMgr::instance().takeOffOutfit(selected_outfit_id); +    } +} + +void LLOutfitListGearMenuBase::onRename() +{ +    const LLUUID& selected_outfit_id = getSelectedOutfitID(); +    if (selected_outfit_id.notNull()) +    { +        LLAppearanceMgr::instance().renameOutfit(selected_outfit_id); +    } +} + +void LLOutfitListGearMenuBase::onCreate(const LLSD& data) +{ +    LLWearableType::EType type = LLWearableType::typeNameToType(data.asString()); +    if (type == LLWearableType::WT_NONE) +    { +        LL_WARNS() << "Invalid wearable type" << LL_ENDL; +        return; +    } + +    LLAgentWearables::createWearable(type, true); +} + +bool LLOutfitListGearMenuBase::onEnable(LLSD::String param) +{ +    // Handle the "Wear - Replace Current Outfit" menu option specially +    // because LLOutfitList::isActionEnabled() checks whether it's allowed +    // to wear selected outfit OR selected items, while we're only +    // interested in the outfit (STORM-183). +    if ("wear" == param) +    { +        return LLAppearanceMgr::instance().getCanReplaceCOF(mOutfitList->getSelectedOutfitUUID()); +    } + +    return mOutfitList->isActionEnabled(param); +} + +bool LLOutfitListGearMenuBase::onVisible(LLSD::String param) +{ +    const LLUUID& selected_outfit_id = getSelectedOutfitID(); +    if (selected_outfit_id.isNull()) // no selection or invalid outfit selected +    { +        return false; +    } + +    // *TODO This condition leads to menu item behavior inconsistent with +    // "Wear" button behavior and should be modified or removed. +    bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id; + +    if ("wear" == param) +    { +        return !is_worn; +    } + +    return true; +} + +void LLOutfitListGearMenuBase::onUploadFoto() +{ + +} + +void LLOutfitListGearMenuBase::onLoadAssets() +{ + +} + +LLOutfitListGearMenu::LLOutfitListGearMenu(LLOutfitListBase* olist) +    : LLOutfitListGearMenuBase(olist) +{} + +void LLOutfitListGearMenu::onUpdateItemsVisibility() +{ +    if (!mMenu) return; +    mMenu->setItemVisible("expand", TRUE); +    mMenu->setItemVisible("collapse", TRUE); +    mMenu->setItemVisible("upload_foto", FALSE); +    mMenu->setItemVisible("load_assets", TRUE); +    LLOutfitListGearMenuBase::onUpdateItemsVisibility(); +} +  // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 2e3fb3f488..f4b02991e5 100755 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -32,11 +32,14 @@  // newview  #include "llinventorymodel.h" +#include "lllistcontextmenu.h"  #include "llpanelappearancetab.h" +#include "lltoggleablemenu.h" +#include "llviewermenu.h"  class LLAccordionCtrlTab;  class LLInventoryCategoriesObserver; -class LLOutfitListGearMenu; +class LLOutfitListGearMenuBase;  class LLWearableItemsList;  class LLListContextMenu; @@ -57,6 +60,134 @@ public:  	/*virtual*/ bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const;  }; +class LLOutfitListBase : public LLPanelAppearanceTab +{ +public: +    typedef boost::function<void(const LLUUID&)> selection_change_callback_t; +    typedef boost::signals2::signal<void(const LLUUID&)> selection_change_signal_t; + +    LLOutfitListBase(); +    virtual ~LLOutfitListBase(); + +    /*virtual*/ BOOL postBuild(); +    /*virtual*/ void onOpen(const LLSD& info); + +    void refreshList(const LLUUID& category_id); +    void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved); +    // highlights currently worn outfit in list and unhighlights previously worn +    void highlightBaseOutfit(); +    void ñhangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id); + + +    virtual void getCurrentCategories(uuid_vec_t& vcur) = 0; +    virtual void updateAddedCategory(LLUUID cat_id) = 0; +    virtual void updateRemovedCategory(LLUUID cat_id) = 0; +    virtual void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name) = 0; +    virtual void sortOutfits(); + +    void removeSelected(); +    void setSelectedOutfitByUUID(const LLUUID& outfit_uuid); +    const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; } +    boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb); +    void outfitRightClickCallBack(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id); + +    virtual bool isActionEnabled(const LLSD& userdata); +    virtual void performAction(std::string action); +    virtual bool hasItemSelected() = 0; +    virtual bool canWearSelected() = 0; + +    void signalSelectionOutfitUUID(const LLUUID& category_id); + +    void collapseAllFolders(); +    virtual void onCollapseAllFolders() = 0; + +    void expandAllFolders(); +    virtual void onExpandAllFolders() = 0; + +    virtual bool getHasExpandableFolders() = 0; + +protected: +    virtual LLOutfitListGearMenuBase* createGearMenu() = 0; +    virtual void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id) = 0; +    virtual void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) = 0; +    virtual void onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) = 0; +    void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response); +    virtual void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) = 0; + +    bool                            mIsInitialized; +    LLInventoryCategoriesObserver* 	mCategoriesObserver;     +    LLUUID							mSelectedOutfitUUID; +    // id of currently highlited outfit +    LLUUID							mHighlightedOutfitUUID; +    selection_change_signal_t		mSelectionChangeSignal; +    LLListContextMenu*				mOutfitMenu; +    LLOutfitListGearMenuBase*		mGearMenu; +}; + +////////////////////////////////////////////////////////////////////////// + +class LLOutfitContextMenu : public LLListContextMenu +{ +public: + +    LLOutfitContextMenu(LLOutfitListBase* outfit_list) +        : LLListContextMenu(), +        mOutfitList(outfit_list) +    {} +protected: +    /* virtual */ LLContextMenu* createMenu(); + +    bool onEnable(LLSD::String param); + +    bool onVisible(LLSD::String param); + +    static void editOutfit(); + +    static void renameOutfit(const LLUUID& outfit_cat_id); + +private: +    LLOutfitListBase*	mOutfitList; +}; + +class LLOutfitListGearMenuBase +{ +public: +    LLOutfitListGearMenuBase(LLOutfitListBase* olist); + +    void updateItemsVisibility(); + +    LLToggleableMenu* getMenu(); + +protected: +    virtual void onUpdateItemsVisibility(); +    virtual void onUploadFoto(); +    virtual void onLoadAssets(); +    const LLUUID& getSelectedOutfitID(); + +    LLOutfitListBase*		mOutfitList; +    LLToggleableMenu*		mMenu; +private: + +    LLViewerInventoryCategory* getSelectedOutfit(); + +    void onWear(); +    void onAdd(); +    void onTakeOff(); +    void onRename(); +    void onCreate(const LLSD& data); +    bool onEnable(LLSD::String param); +    bool onVisible(LLSD::String param); +}; + +class LLOutfitListGearMenu : public LLOutfitListGearMenuBase +{ +public: +    LLOutfitListGearMenu(LLOutfitListBase* olist); + +protected: +    /*virtual*/ void onUpdateItemsVisibility(); +}; +  /**   * @class LLOutfitsList   * @@ -66,11 +197,9 @@ public:   *   * Starts fetching necessary inventory content on first opening.   */ -class LLOutfitsList : public LLPanelAppearanceTab +class LLOutfitsList : public LLOutfitListBase  {  public: -	typedef boost::function<void (const LLUUID&)> selection_change_callback_t; -	typedef boost::signals2::signal<void (const LLUUID&)> selection_change_signal_t;  	LLOutfitsList();  	virtual ~LLOutfitsList(); @@ -79,63 +208,66 @@ public:  	/*virtual*/ void onOpen(const LLSD& info); -	void refreshList(const LLUUID& category_id); - -	// highlits currently worn outfit tab text and unhighlights previously worn -	void highlightBaseOutfit(); -	void performAction(std::string action); +    //virtual void refreshList(const LLUUID& category_id); -	void removeSelected(); +    /*virtual*/ void updateAddedCategory(LLUUID cat_id); +    /*virtual*/ void updateRemovedCategory(LLUUID cat_id); -	void setSelectedOutfitByUUID(const LLUUID& outfit_uuid); +	// highlits currently worn outfit tab text and unhighlights previously worn +    /*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id); -	/*virtual*/ void setFilterSubString(const std::string& string); +	//void performAction(std::string action); -	/*virtual*/ bool isActionEnabled(const LLSD& userdata); -	const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; } +	/*virtual*/ void setFilterSubString(const std::string& string);  	/*virtual*/ void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const; -	boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb); - -	// Collects selected items from all selected lists and wears them(if possible- adds, else replaces) +    // Collects selected items from all selected lists and wears them(if possible- adds, else replaces)  	void wearSelectedItems();  	/**  	 * Returns true if there is a selection inside currently selected outfit  	 */ -	bool hasItemSelected(); +    /*virtual*/ bool hasItemSelected();  	/**  	Collapses all outfit accordions.  	*/ -	void collapse_all_folders(); +	/*virtual*/ void onCollapseAllFolders();  	/**  	Expands all outfit accordions.  	*/ -	void expand_all_folders(); +	void onExpandAllFolders(); +    /*virtual*/ bool getHasExpandableFolders() { return TRUE; } -private: +protected: +    LLOutfitListGearMenuBase* createGearMenu(); -	void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response); +private:  	/**  	 * Wrapper for LLCommonUtils::computeDifference. @see LLCommonUtils::computeDifference  	 */ -	void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved); +	//void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved); + +    void getCurrentCategories(uuid_vec_t& vcur);  	/**  	 * Updates tab displaying outfit identified by category_id.  	 */ -	void updateOutfitTab(const LLUUID& category_id); +    /*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name); + +    /*virtual*/ void sortOutfits(); + +    /*virtual*/ void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid);  	/**  	 * Resets previous selection and stores newly selected list and outfit id.  	 */ -	void changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id); +    /*virtual*/ void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);  	/**  	 *Resets items selection inside outfit @@ -143,11 +275,6 @@ private:  	void resetItemSelection(LLWearableItemsList* list, const LLUUID& category_id);  	/** -	 * Saves newly selected outfit ID. -	 */ -	void setSelectedOutfitUUID(const LLUUID& category_id); - -	/**  	 * Removes the outfit from selection.  	 */  	void deselectOutfit(const LLUUID& category_id); @@ -182,15 +309,16 @@ private:  	 */  	bool canWearSelected(); -	void onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);  	void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);  	void onCOFChanged(); -	void onSelectionChange(LLUICtrl* ctrl); +	void onListSelectionChange(LLUICtrl* ctrl); + +    /*virtual*/ void onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);  	static void onOutfitRename(const LLSD& notification, const LLSD& response); -	LLInventoryCategoriesObserver* 	mCategoriesObserver; +	//LLInventoryCategoriesObserver* 	mCategoriesObserver;  	LLAccordionCtrl*				mAccordion;  	LLPanel*						mListCommands; @@ -199,11 +327,6 @@ private:  	typedef wearables_lists_map_t::value_type			wearables_lists_map_value_t;  	wearables_lists_map_t			mSelectedListsMap; -	LLUUID							mSelectedOutfitUUID; -	// id of currently highlited outfit -	LLUUID							mHighlightedOutfitUUID; -	selection_change_signal_t		mSelectionChangeSignal; -  	typedef	std::map<LLUUID, LLAccordionCtrlTab*>		outfits_map_t;  	typedef outfits_map_t::value_type					outfits_map_value_t;  	outfits_map_t					mOutfitsMap; @@ -212,10 +335,9 @@ private:  	// Used to monitor COF changes for updating items worn state. See EXT-8636.  	uuid_vec_t						mCOFLinkedItems; -	LLOutfitListGearMenu*			mGearMenu; -	LLListContextMenu*				mOutfitMenu; +	//LLOutfitListGearMenu*			mGearMenu; -	bool							mIsInitialized; +	//bool							mIsInitialized;  	/**  	 * True if there is a selection inside currently selected outfit  	 */ diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 1e1f59055f..eb88abb2bf 100755 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -37,6 +37,7 @@  #include "llagentwearables.h"  #include "llappearancemgr.h"  #include "lloutfitobserver.h" +#include "lloutfitgallery.h"  #include "lloutfitslist.h"  #include "llpanelwearing.h"  #include "llsaveoutfitcombobtn.h" @@ -44,6 +45,7 @@  #include "llviewerfoldertype.h"  static const std::string OUTFITS_TAB_NAME = "outfitslist_tab"; +static const std::string OUTFIT_GALLERY_TAB_NAME = "outfit_gallery_tab";  static const std::string COF_TAB_NAME = "cof_tab";  static LLPanelInjector<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory"); @@ -268,12 +270,16 @@ bool LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)  void LLPanelOutfitsInventory::initTabPanels()  { +    //TODO: Add LLOutfitGallery change callback  	mCurrentOutfitPanel = findChild<LLPanelWearing>(COF_TAB_NAME);  	mCurrentOutfitPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this));  	mMyOutfitsPanel = findChild<LLOutfitsList>(OUTFITS_TAB_NAME);  	mMyOutfitsPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); +    mOutfitGalleryPanel = findChild<LLOutfitGallery>(OUTFIT_GALLERY_TAB_NAME); +    mOutfitGalleryPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); +  	mAppearanceTabs = getChild<LLTabContainer>("appearance_tabs");  	mAppearanceTabs->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::onTabChange, this));  } diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index a7917b457c..8c873df038 100755 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -30,8 +30,9 @@  #include "llpanel.h" +class LLOutfitGallery;  class LLOutfitsList; -class LLOutfitListGearMenu; +class LLOutfitListGearMenuBase;  class LLPanelAppearanceTab;  class LLPanelWearing;  class LLMenuGL; @@ -76,6 +77,7 @@ protected:  private:  	LLPanelAppearanceTab*	mActivePanel;  	LLOutfitsList*			mMyOutfitsPanel; +    LLOutfitGallery*        mOutfitGalleryPanel;  	LLPanelWearing*			mCurrentOutfitPanel;  	// tab panels                                                                   // diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 980810835e..1e9d0f912f 100755 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -71,6 +71,7 @@  #include "llradiogroup.h"  #include "llfloaterreg.h"  #include "lllocalbitmaps.h" +#include "llerror.h"  static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;  static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f; @@ -573,6 +574,7 @@ void LLFloaterTexturePicker::draw()  		mTexturep = NULL;  		if(mImageAssetID.notNull())  		{ +            LL_WARNS() << "mImageAssetID: " << mImageAssetID << LL_ENDL;  			mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID);  			mTexturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);  		} diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index 8533625e50..e0da7f5d9e 100755 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -948,4 +948,13 @@    <color      name="SyntaxLslStringLiteral"      value="1 0.14 0 1" /> +  <color +    name="OutfitGalleryItemSelected" +    value="0.22 0.45 0.35 1" /> +  <color +    name="OutfitGalleryItemWorn" +    value="0.33 0.58 0.47 1" /> +  <color +    name="OutfitGalleryItemUnselected" +    value="0.4 0.4 0.4 1" />  </colors> diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index e453d94883..1b7b76e3b8 100755 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -804,6 +804,7 @@ with the same filename but different name    <texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/>    <texture name="NavBar Separator" file_name="navbar/separator.png"/> +  <texture name="Outfit_Default_Foto" fileName="icons/pop_up_caution.png"/>    <texture name="Notification_Condense" file_name="icons/Icon_Notification_Condense.png" preload="true"/>    <texture name="Notification_Expand" file_name="icons/Icon_Notification_Expand.png" preload="true"/>    <texture name="System_Notification" file_name="icons/SL_Logo.png" preload="true"/> diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml index 76adaad57c..420aced6a2 100755 --- a/indra/newview/skins/default/xui/en/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -406,7 +406,7 @@  	width="400"  	height="400"      follows="top|left"/> -  <view_border  +  <!--view_border      bevel_style="in"      height="21"     layout="topleft" @@ -414,7 +414,7 @@     top_pad="0"     right="-10"     follows="left|top|right" -   left_delta="0"/> +   left_delta="0"/>-->     <text      type="string"      font="SansSerifSmall" 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 3b8ace6308..c970efbc03 100755 --- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml @@ -39,8 +39,22 @@           function="Gear.OnVisible"           parameter="take_off" />      </menu_item_call> +    <menu_item_call +     label="Upload foto" +     layout="topleft" +     name="upload_foto"> +        <on_click +         function="Gear.UploadFoto" /> +    </menu_item_call> +    <menu_item_call +     label="Load assets" +     layout="topleft" +     name="load_assets"> +        <on_click +         function="Gear.LoadAssets" /> +    </menu_item_call> -            <menu_item_separator name="sepatator1" /> +  <menu_item_separator name="sepatator1" />              <!-- copied (with minor modifications) from menu_inventory_add.xml -->              <!--  *TODO: generate dynamically? -->              <menu diff --git a/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml new file mode 100644 index 0000000000..2a06b35942 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +   background_visible="true" +   bg_alpha_color="DkGray" +   border="false" +   follows="all" +   height="430" +   name="Outfit Gallery" +   layout="topleft" +   left="0" +   top="0" +   width="312"> +  <string name="outfit_foto_string"> +    Foto of "[OUTFIT_NAME]" outfit +  </string> +  <scroll_container +   border="true" +   bevel_style="none" +   follows="all" +   height="400" +   width="312" +   min_width="312" +   layout="topleft" +   left="4" +   top="0" +   name="gallery_scroll_panel" +   opaque="false" +   top_pad="0"> +   <!--outfit_gallery_item +    layout="topleft" +    left="10" +    name="preview_outfit1" +    height="175" +    width="150" +    follows="left|top"/--> +     <!--layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="0" name="top_gallery_stack" orientation="horizontal"> +      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel"> +        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/> +      </layout_panel> +      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel"> +        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/> +      </layout_panel> +      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel"> +        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/> +      </layout_panel> +    </layout_stack> +    <layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="190" name="top_gallery_stack" orientation="horizontal"> +      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel"> +        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/> +      </layout_panel> +      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel"> +        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/> +      </layout_panel> +      <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel"> +        <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/> +      </layout_panel> +    </layout_stack> +     <layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="380" name="top_gallery_stack" orientation="horizontal"> +       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel"> +         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/> +       </layout_panel> +       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel"> +         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/> +       </layout_panel> +       <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel"> +         <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/> +       </layout_panel> +     </layout_stack--> +    <!--</panel>--> +  </scroll_container> +  <panel +     background_visible="true" +	 follows="bottom|left|right" +	 height="28" +	 layout="topleft" +	 left="4" +	 top_pad="0" +	 visible="true" +	 name="bottom_panel" +	 width="312"> +     <menu_button +       follows="bottom|left" +       tool_tip="Show additional options" +       height="25" +       image_hover_unselected="Toolbar_Left_Over" +       image_overlay="OptionsMenu_Off" +       image_selected="Toolbar_Left_Selected" +       image_unselected="Toolbar_Left_Off" +       layout="topleft" +       left="0" +       name="options_gear_btn" +       top="1" +       width="31" /> +     <icon +       follows="bottom|left|right" +       height="25" +       image_name="Toolbar_Middle_Off" +       layout="topleft" +       left_pad="1" +       name="dummy_icon" +       width="243"/> +      <button +       follows="bottom|right" +       height="25" +       image_hover_unselected="Toolbar_Right_Over" +       image_overlay="TrashItem_Off" +       image_selected="Toolbar_Right_Selected" +       image_unselected="Toolbar_Right_Off" +       layout="topleft" +       left_pad="1" +       name="trash_btn" +       tool_tip="Delete selected outfit" +       width="31"/> +    </panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml b/indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml new file mode 100644 index 0000000000..7c3e93fdae --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +   background_visible="false" +   background_opaque="false" +   bg_alpha_color="FrogGreen" +   bg_opaque_color="FrogGreen" +   border_color="Red" +   border="false" +   bevel_style="none" +   follows="left|top" +   height="169" +   width="150" +   name="gallery_item_panel" +   layout="topleft" +   left="0" +   top="0" +   > +  <string name="worn_string"> +    (worn) +  </string> +  <icon +      left="1" +      top="0" +      layout="topleft" +      name="preview_outfit" +      height="149" +      width="147" +      follows="left|top" +      visible="true" +      image_name="Popup_Caution" +    /> +  <panel +   background_visible="false" +   background_opaque="true" +   bg_opaque_color="OutfitGalleryItemSelected" +   border="false" +   bevel_style="none" +   follows="left|top" +   left="0" +   top="149" +   height="25" +   width="148" +   name="text_bg_panel" +   > +    <text +      read_only="true" +      length="1" +      follows="left|top" +      left="1" +      height="10" +      layout="topleft" +      name="outfit_name" +      top="0" +      width="150"> +      Summer hipster, Pierce +    </text> +    <text +      read_only="true" +      length="1" +      follows="left|top" +      left="1" +      height="10" +      layout="topleft" +      name="outfit_worn_text" +      top="10" +      width="150"> +      (worn) +    </text> +  </panel> + +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml index 405d9513db..ff0714adbb 100755 --- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml @@ -33,6 +33,17 @@       top="8"       width="315">           <panel +           class="outfit_gallery" +           filename="panel_outfit_gallery.xml" +           height="520" +           name="outfit_gallery_tab" +           background_visible="true" +           help_topic="outfit_gallery_tab" +           follows="all" +           label="OUTFIT GALLERY" +           layout="topleft" +           width="315" /> +         <panel             class="outfits_list"             filename="panel_outfits_list.xml"             height="520"  | 
