From 6a02f5bbcec2b1a530ceeacb0dc564cfeb7cbc7f Mon Sep 17 00:00:00 2001 From: pavelkproductengine Date: Fri, 11 Dec 2015 19:58:08 +0200 Subject: Initial version of Visual Outfit Browser --- indra/llui/llfocusmgr.cpp | 1 - indra/llui/lllayoutstack.cpp | 2 +- indra/newview/CMakeLists.txt | 2 + indra/newview/lloutfitgallery.cpp | 699 +++++++++++ indra/newview/lloutfitgallery.h | 152 +++ indra/newview/lloutfitslist.cpp | 1234 +++++++++++++------- indra/newview/lloutfitslist.h | 204 +++- indra/newview/llpaneloutfitsinventory.cpp | 6 + indra/newview/llpaneloutfitsinventory.h | 4 +- indra/newview/lltexturectrl.cpp | 2 + indra/newview/skins/default/textures/textures.xml | 1 + .../skins/default/xui/en/floater_snapshot.xml | 4 +- .../skins/default/xui/en/menu_outfit_gear.xml | 16 +- .../skins/default/xui/en/panel_outfit_gallery.xml | 128 ++ .../default/xui/en/panel_outfit_gallery_item.xml | 49 + .../default/xui/en/panel_outfits_inventory.xml | 11 + 16 files changed, 2022 insertions(+), 493 deletions(-) create mode 100644 indra/newview/lloutfitgallery.cpp create mode 100644 indra/newview/lloutfitgallery.h create mode 100644 indra/newview/skins/default/xui/en/panel_outfit_gallery.xml create mode 100644 indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 547f0bd398..87c50ad465 100755 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -168,7 +168,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 536c7740bb..f18d9f04f9 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -414,6 +414,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 llnotificationhandler.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..2d8085e128 --- /dev/null +++ b/indra/newview/lloutfitgallery.cpp @@ -0,0 +1,699 @@ +/** + * @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 + +// 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 t_outfit_gallery("outfit_gallery"); +static LLOutfitGallery* gOutfitGallery = NULL; + +LLOutfitGallery::LLOutfitGallery() + : LLOutfitListBase(), + mTexturesObserver(NULL) +{ +// mGearMenu = new LLOutfitGalleryGearMenu(this); +} + +BOOL LLOutfitGallery::postBuild() +{ + BOOL rv = LLOutfitListBase::postBuild(); + return rv; +} + +void LLOutfitGallery::onOpen(const LLSD& info) +{ + LLOutfitListBase::onOpen(info); + rebuildGallery(); + loadPhotos(); +} + +#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 + +void LLOutfitGallery::rebuildGallery() +{ + LLView::child_list_t child_list(*getChild("gallery_panel")->getChildList()); + BOOST_FOREACH(LLView* view, child_list) + { + LLLayoutStack* lstack = dynamic_cast(view); + if (lstack != NULL) + { + LLView::child_list_t panel_list(*lstack->getChildList()); + BOOST_FOREACH(LLView* panel, panel_list) + { + //LLLayoutPanel* lpanel = dynamic_cast(panel); + //if (!lpanel) + // continue; + LLView::child_list_t panel_children(*panel->getChildList()); + if (panel_children.size() > 0) + { + //Assume OutfitGalleryItem is the only one child of layout panel + LLView* view_item = panel_children.back(); + LLOutfitGalleryItem* gallery_item = dynamic_cast(view_item); + if (gallery_item != NULL) + panel->removeChild(gallery_item); + } + lstack->removeChild(panel); + //delete panel; + } + getChild("gallery_panel")->removeChild(lstack); + delete lstack; + } + else + { + getChild("gallery_panel")->removeChild(view); + } + } + uuid_vec_t cats; + getCurrentCategories(cats); + int n = cats.size(); + int row_count = (n % ITEMS_IN_ROW) == 0 ? n / ITEMS_IN_ROW : n / ITEMS_IN_ROW + 1; + getChild("gallery_panel")->reshape( + GALLERY_WIDTH, row_count * (LAYOUT_STACK_HEIGHT + GALLERY_VERTICAL_GAP)); + int vgap = 0; + uuid_vec_t::reverse_iterator rit = cats.rbegin(); + for (int i = row_count - 1; i >= 0; i--) + { + LLLayoutStack* stack = buildLayoutStak(0, (row_count - 1 - i) * LAYOUT_STACK_HEIGHT + vgap); + getChild("gallery_panel")->addChild(stack); + int items_in_cur_row = (n % ITEMS_IN_ROW) == 0 ? ITEMS_IN_ROW : (i == row_count - 1 ? n % ITEMS_IN_ROW : ITEMS_IN_ROW); + int hgap = 0; + for (int j = 0; j < items_in_cur_row && rit != cats.rend(); j++) + { + LLLayoutPanel* lpanel = buildLayoutPanel(j * GALLERY_ITEM_WIDTH + hgap); + LLOutfitGalleryItem* item = mOutfitMap[*rit]; + lpanel->addChild(item); + stack->addChild(lpanel); + rit++; + hgap += GALLERY_HORIZONTAL_GAP; + } + vgap += GALLERY_VERTICAL_GAP; + } +} + +LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name) +{ + LLOutfitGalleryItem::Params giparams; + LLOutfitGalleryItem* gitem = LLUICtrlFactory::create(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; +} + +LLLayoutPanel* LLOutfitGallery::buildLayoutPanel(int left) +{ + LLLayoutPanel::Params lpparams; + int top = 0; + LLLayoutPanel* lpanel = LLUICtrlFactory::create(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; +} + +LLLayoutStack* LLOutfitGallery::buildLayoutStak(int left, int top) +{ + LLLayoutStack::Params sparams; + LLLayoutStack* stack = LLUICtrlFactory::create(sparams); + LLRect rect = LLRect(left, top + LAYOUT_STACK_HEIGHT, left + LAYOUT_STACK_WIDTH, top); + stack->setRect(rect); + stack->reshape(LAYOUT_STACK_WIDTH, LAYOUT_STACK_HEIGHT); + stack->setVisible(true); + stack->setFollowsLeft(); + stack->setFollowsTop(); + return stack; +} + + +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)); + +} + +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. + rebuildGallery(); + + // 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 r("outfit_gallery_item"); + +LLOutfitGalleryItem::LLOutfitGalleryItem(const Params& p) + : LLPanel(p), + mTexturep(NULL) +{ + buildFromFile("panel_outfit_gallery_item.xml"); +} + +LLOutfitGalleryItem::~LLOutfitGalleryItem() +{ + +} + +BOOL LLOutfitGalleryItem::postBuild() +{ + setDefaultImage(); + + mOutfitNameText = getChild("outfit_name"); + mOutfitWornText = getChild("outfit_worn_text"); + setOutfitWorn(false); + return TRUE; +} + +void LLOutfitGalleryItem::draw() +{ + LLPanel::draw(); + + // In case texture is not set, don't draw it over default image + if (!mTexturep) + { + return; + } + + // Border + LLRect border = getChildView("preview_outfit")->getRect(); + //gl_rect_2d(border, LLColor4::black, FALSE); + + + // Interior + LLRect interior = border; + //interior.stretch(-1); + + // 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); + } + + gl_draw_scaled_image(interior.mLeft, 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) +{ + //LLStringUtil::format_map_t string_args; + //std::string worn_text = getString("worn_text", string_args); + + if (value) + { + mOutfitWornText->setValue("(worn)"); + } + else + { + mOutfitWornText->setValue(""); + } +} + +void LLOutfitGalleryItem::setSelected(bool value) +{ + if (value) + { + mOutfitWornText->setValue("(selected)"); + } + else + { + mOutfitWornText->setValue(""); + } +} + +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(mOutfitList); + if (gallery && selected_outfit_id.notNull()) + { + gallery->uploadPhoto(selected_outfit_id); + } + if (selected_outfit_id.notNull()) + { + + } +} + +void LLOutfitGalleryGearMenu::onLoadAssets() +{ + LLOutfitGallery* gallery = dynamic_cast(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..93b9ba1e3f --- /dev/null +++ b/indra/newview/lloutfitgallery.h @@ -0,0 +1,152 @@ +/** + * @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 + +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 rebuildGallery(); + void loadPhotos(); + void uploadPhoto(LLUUID outfit_id); + bool checkRemovePhoto(LLUUID outfit_id); + void setUploadedPhoto(LLUUID outfit_id, LLUUID asset_id); + + 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); + LLLayoutPanel* buildLayoutPanel(int left); + LLLayoutStack* buildLayoutStak(int left, int top); + + LLView* mView; + std::vector mLayouts; + std::vector mPanels; + std::vector mItems; + + typedef std::map outfit_map_t; + typedef outfit_map_t::value_type outfit_map_value_t; + outfit_map_t mOutfitMap; + typedef std::map texture_map_t; + typedef texture_map_t::value_type texture_map_value_t; + texture_map_t mTextureMap; + + 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 + {}; + + 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 mTexturep; + LLTextBox* mOutfitNameText; + LLTextBox* mOutfitWornText; +}; + +#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 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( - "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("outfits_accordion"); + mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR); -private: - const LLUUID& getSelectedOutfitID() - { - return mOutfitList->getSelectedOutfitUUID(); - } + //LLMenuButton* menu_gear_btn = getChild("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(tab_params); + if (!tab) return; + LLWearableItemsList* wearable_list = LLUICtrlFactory::create(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("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 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("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("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(tab_params); - if (!tab) continue; - LLWearableItemsList* wearable_list = LLUICtrlFactory::create(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(tab_params); + //if (!tab) continue; + //LLWearableItemsList* wearable_list = LLUICtrlFactory::create(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("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("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(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(ctrl); - if(mOutfitMenu && is_tab_header_clicked(tab, y) && cat_id.notNull()) - { - // Focus tab header to trigger tab selection change. - LLUICtrl* header = tab->findChild("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(ctrl); + if (mOutfitMenu && is_tab_header_clicked(tab, y) && cat_id.notNull()) + { + // Focus tab header to trigger tab selection change. + LLUICtrl* header = tab->findChild("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("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( + "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 selection_change_callback_t; + typedef boost::signals2::signal 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 selection_change_callback_t; - typedef boost::signals2::signal selection_change_signal_t; LLOutfitsList(); virtual ~LLOutfitsList(); @@ -79,74 +208,72 @@ 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 */ void resetItemSelection(LLWearableItemsList* list, const LLUUID& category_id); - /** - * Saves newly selected outfit ID. - */ - void setSelectedOutfitUUID(const LLUUID& category_id); - /** * Removes the outfit from selection. */ @@ -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 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 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(COF_TAB_NAME); mCurrentOutfitPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); mMyOutfitsPanel = findChild(OUTFITS_TAB_NAME); mMyOutfitsPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); + mOutfitGalleryPanel = findChild(OUTFIT_GALLERY_TAB_NAME); + mOutfitGalleryPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); + mAppearanceTabs = getChild("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/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index a5f2ce1f84..56def93ffe 100755 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -804,4 +804,5 @@ with the same filename but different name + 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"/> - + left_delta="0"/>--> + + + + + + - + + + + Foto of "[OUTFIT_NAME]" outfit + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3 From 0a73840dd8e350cd936b681c0cc5131905eb3b09 Mon Sep 17 00:00:00 2001 From: Mnikolenko ProductEngine Date: Thu, 5 May 2016 16:30:41 +0300 Subject: MAINT-6381 Right click on Outfit Folder behavior --- indra/newview/lloutfitgallery.cpp | 103 ++++++++++++++++++++- indra/newview/lloutfitgallery.h | 27 ++++++ .../default/xui/en/panel_outfit_gallery_item.xml | 3 +- 3 files changed, 130 insertions(+), 3 deletions(-) diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index b351be8de9..a36728e6ac 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -44,6 +44,7 @@ #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "lllocalbitmaps.h" +#include "llnotificationsutil.h" #include "lltexturectrl.h" #include "llviewermenufile.h" #include "llwearableitemslist.h" @@ -98,6 +99,7 @@ BOOL LLOutfitGallery::postBuild() BOOL rv = LLOutfitListBase::postBuild(); mScrollPanel = getChild("gallery_scroll_panel"); mGalleryPanel = getChild("gallery_panel"); + mOutfitGalleryMenu = new LLOutfitGalleryContextMenu(this); return rv; } @@ -352,6 +354,8 @@ void LLOutfitGallery::moveRowPanel(LLPanel* stack, int left, int bottom) LLOutfitGallery::~LLOutfitGallery() { + delete mOutfitGalleryMenu; + if (gInventory.containsObserver(mTexturesObserver)) { gInventory.removeObserver(mTexturesObserver); @@ -486,7 +490,7 @@ void LLOutfitGallery::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLU { uuid_vec_t selected_uuids; selected_uuids.push_back(cat_id); - mOutfitMenu->show(ctrl, selected_uuids, x, y); + mOutfitGalleryMenu->show(ctrl, selected_uuids, x, y); } } @@ -604,6 +608,12 @@ BOOL LLOutfitGalleryItem::handleMouseDown(S32 x, S32 y, MASK mask) return LLUICtrl::handleMouseDown(x, y, mask); } +BOOL LLOutfitGalleryItem::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + setFocus(TRUE); + return LLUICtrl::handleRightMouseDown(x, y, mask); +} + void LLOutfitGalleryItem::setImageAssetId(LLUUID image_asset_id) { mImageAssetId = image_asset_id; @@ -626,6 +636,97 @@ void LLOutfitGalleryItem::setDefaultImage() mDefaultImage = true; } +LLContextMenu* LLOutfitGalleryContextMenu::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(&LLOutfitGalleryContextMenu::onRemoveOutfit, this, selected_id)); + registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2)); + registrar.add("Outfit.UploadPhoto", boost::bind(&LLOutfitGalleryContextMenu::onUploadPhoto, this, selected_id)); + registrar.add("Outfit.SelectPhoto", boost::bind(&LLOutfitGalleryContextMenu::onSelectPhoto, this, selected_id)); + registrar.add("Outfit.TakeSnapshot", boost::bind(&LLOutfitGalleryContextMenu::onTakeSnapshot, this, selected_id)); + + enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2)); + enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2)); + + return createFromFile("menu_gallery_outfit_tab.xml"); +} + +void LLOutfitGalleryContextMenu::onUploadPhoto(const LLUUID& outfit_cat_id) +{ + LLOutfitGallery* gallery = dynamic_cast(mOutfitList); + if (gallery && outfit_cat_id.notNull()) + { + gallery->uploadPhoto(outfit_cat_id); + } +} + +void LLOutfitGalleryContextMenu::onSelectPhoto(const LLUUID& outfit_cat_id) +{ + LLOutfitGallery* gallery = dynamic_cast(mOutfitList); + if (gallery && outfit_cat_id.notNull()) + { + gallery->onSelectPhoto(outfit_cat_id); + } +} + +void LLOutfitGalleryContextMenu::onTakeSnapshot(const LLUUID& outfit_cat_id) +{ + LLOutfitGallery* gallery = dynamic_cast(mOutfitList); + if (gallery && outfit_cat_id.notNull()) + { + gallery->onTakeSnapshot(outfit_cat_id); + } +} + +void LLOutfitGalleryContextMenu::onRemoveOutfit(const LLUUID& outfit_cat_id) +{ + LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLOutfitGalleryContextMenu::onOutfitsRemovalConfirmation, this, _1, _2, outfit_cat_id)); +} + +void LLOutfitGalleryContextMenu::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return; // canceled + + if (outfit_cat_id.notNull()) + { + gInventory.removeCategory(outfit_cat_id); + } +} + +void LLOutfitGalleryContextMenu::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 LLOutfitGalleryContextMenu::onEnable(LLSD::String param) +{ + return LLOutfitContextMenu::onEnable(param); +} + +bool LLOutfitGalleryContextMenu::onVisible(LLSD::String param) +{ + return LLOutfitContextMenu::onVisible(param); +} + LLOutfitGalleryGearMenu::LLOutfitGalleryGearMenu(LLOutfitListBase* olist) : LLOutfitListGearMenuBase(olist) { diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index dbf891142d..b8c7d66406 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -43,6 +43,7 @@ class LLOutfitGallery; class LLOutfitGalleryItem; class LLOutfitListGearMenuBase; class LLOutfitGalleryGearMenu; +class LLOutfitGalleryContextMenu; class LLUpdateGalleryOnPhotoLinked : public LLInventoryCallback { @@ -57,6 +58,7 @@ class LLOutfitGallery : public LLOutfitListBase { public: friend class LLOutfitGalleryGearMenu; + friend class LLOutfitGalleryContextMenu; friend class LLUpdateGalleryOnPhotoLinked; struct Params @@ -169,6 +171,8 @@ private: int mGalleryWidth; int mRowPanWidthFactor; int mGalleryWidthFactor; + + LLListContextMenu* mOutfitGalleryMenu; LLHandle mFloaterHandle; @@ -183,6 +187,28 @@ private: LLInventoryCategoriesObserver* mTexturesObserver; LLInventoryCategoriesObserver* mOutfitsObserver; }; +class LLOutfitGalleryContextMenu : public LLOutfitContextMenu +{ +public: + + friend class LLOutfitGallery; + LLOutfitGalleryContextMenu(LLOutfitListBase* outfit_list) + : LLOutfitContextMenu(outfit_list), + mOutfitList(outfit_list){} +protected: + /* virtual */ LLContextMenu* createMenu(); + bool onEnable(LLSD::String param); + bool onVisible(LLSD::String param); + void onUploadPhoto(const LLUUID& outfit_cat_id); + void onSelectPhoto(const LLUUID& outfit_cat_id); + void onTakeSnapshot(const LLUUID& outfit_cat_id); + void onCreate(const LLSD& data); + void onRemoveOutfit(const LLUUID& outfit_cat_id); + void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response, const LLUUID& outfit_cat_id); +private: + LLOutfitListBase* mOutfitList; +}; + class LLOutfitGalleryGearMenu : public LLOutfitListGearMenuBase { @@ -210,6 +236,7 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void draw(); /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); void setDefaultImage(); void setImageAssetId(LLUUID asset_id); 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 index eede209e91..77c546c6e7 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml @@ -3,8 +3,7 @@ background_visible="false" background_opaque="false" bg_alpha_color="FrogGreen" - bg_opaque_color="FrogGreen" - border_color="Red" + bg_opaque_color="FrogGreen" border="false" bevel_style="none" follows="left|top" -- cgit v1.2.3 From bdeeb6451fcfaabb826a6a8babe9f580643bc873 Mon Sep 17 00:00:00 2001 From: Mnikolenko ProductEngine Date: Thu, 5 May 2016 16:32:12 +0300 Subject: MAINT-6381 Right click on Outfit Folder behavior --- .../default/xui/en/menu_gallery_outfit_tab.xml | 246 +++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100755 indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml new file mode 100755 index 0000000000..b9e29788dc --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 8b3f4ec5f58c1488ac7b3403a1a510a4977cebf6 Mon Sep 17 00:00:00 2001 From: pavelkproductengine Date: Thu, 5 May 2016 19:43:02 +0300 Subject: MAINT-6226 Incorporate a customized Snapshot feature to Outfit Browser flow Removed odd controls like custom resolution spinners etc --- indra/newview/llfloateroutfitsnapshot.cpp | 382 +-------------------- indra/newview/llfloateroutfitsnapshot.h | 6 - indra/newview/llpanelsnapshot.cpp | 33 +- indra/newview/llpanelsnapshot.h | 2 +- indra/newview/llpanelsnapshotinventory.cpp | 50 +-- .../default/xui/en/floater_outfit_snapshot.xml | 63 ---- .../xui/en/panel_outfit_snapshot_inventory.xml | 52 +-- 7 files changed, 58 insertions(+), 530 deletions(-) diff --git a/indra/newview/llfloateroutfitsnapshot.cpp b/indra/newview/llfloateroutfitsnapshot.cpp index 8fa54e7f94..cea0e48aa6 100644 --- a/indra/newview/llfloateroutfitsnapshot.cpp +++ b/indra/newview/llfloateroutfitsnapshot.cpp @@ -105,20 +105,13 @@ public: static void onCommitLayerTypes(LLUICtrl* ctrl, void*data); static void onImageQualityChange(LLFloaterOutfitSnapshot* view, S32 quality_val); static void onImageFormatChange(LLFloaterOutfitSnapshot* view); - static void applyCustomResolution(LLFloaterOutfitSnapshot* view, S32 w, S32 h); static void onSnapshotUploadFinished(bool status); static void onSendingPostcardFinished(bool status); static BOOL checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL isWidthChanged, S32 max_value); - static void setImageSizeSpinnersValues(LLFloaterOutfitSnapshot *view, S32 width, S32 height) ; - static void updateSpinners(LLFloaterOutfitSnapshot* view, LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL is_width_changed); static LLPanelSnapshot* getActivePanel(LLFloaterOutfitSnapshot* floater, bool ok_if_not_found = true); static LLPanelSnapshot::ESnapshotType getActiveSnapshotType(LLFloaterOutfitSnapshot* floater); static LLFloaterOutfitSnapshot::ESnapshotFormat getImageFormat(LLFloaterOutfitSnapshot* floater); - static LLSpinCtrl* getWidthSpinner(LLFloaterOutfitSnapshot* floater); - static LLSpinCtrl* getHeightSpinner(LLFloaterOutfitSnapshot* floater); - static void enableAspectRatioCheckbox(LLFloaterOutfitSnapshot* floater, BOOL enable); - static void setAspectRatioCheckboxValue(LLFloaterOutfitSnapshot* floater, BOOL checked); static LLSnapshotLivePreview* getPreviewView(LLFloaterOutfitSnapshot *floater); static void setResolution(LLFloaterOutfitSnapshot* floater, const std::string& comboname); @@ -130,9 +123,7 @@ public: private: static LLViewerWindow::ESnapshotType getLayerType(LLFloaterOutfitSnapshot* floater); - static void comboSetCustom(LLFloaterOutfitSnapshot *floater, const std::string& comboname); static void checkAutoSnapshot(LLSnapshotLivePreview* floater, BOOL update_thumbnail = FALSE); - static void checkAspectRatio(LLFloaterOutfitSnapshot *view, S32 index) ; static void setWorking(LLFloaterOutfitSnapshot* floater, bool working); static void setFinished(LLFloaterOutfitSnapshot* floater, bool finished, bool ok = true, const std::string& msg = LLStringUtil::null); @@ -165,79 +156,15 @@ LLPanelSnapshot* LLFloaterOutfitSnapshot::Impl::getActivePanel(LLFloaterOutfitSn // static LLPanelSnapshot::ESnapshotType LLFloaterOutfitSnapshot::Impl::getActiveSnapshotType(LLFloaterOutfitSnapshot* floater) { - //LLSnapshotLivePreview::ESnapshotType type = LLSnapshotLivePreview::SNAPSHOT_WEB; - //std::string name; - LLPanelSnapshot* spanel = getActivePanel(floater); - - //if (spanel) - //{ - // name = spanel->getName(); - //} - - //if (name == "panel_snapshot_postcard") - //{ - // type = LLSnapshotLivePreview::SNAPSHOT_POSTCARD; - //} - //else if (name == "panel_snapshot_inventory") - //{ - // type = LLSnapshotLivePreview::SNAPSHOT_TEXTURE; - //} - //else if (name == "panel_snapshot_local") - //{ - // type = LLSnapshotLivePreview::SNAPSHOT_LOCAL; - //} - - //return type; - if (spanel) - { - return spanel->getSnapshotType(); - } - return LLPanelSnapshot::SNAPSHOT_WEB; + return LLPanelSnapshot::SNAPSHOT_TEXTURE; } // static LLFloaterOutfitSnapshot::ESnapshotFormat LLFloaterOutfitSnapshot::Impl::getImageFormat(LLFloaterOutfitSnapshot* floater) { - //LLPanelSnapshot* active_panel = getActivePanel(floater); - // FIXME: if the default is not PNG, profile uploads may fail. - //return active_panel ? active_panel->getImageFormat() : LLFloaterOutfitSnapshot::SNAPSHOT_FORMAT_PNG; return LLFloaterOutfitSnapshot::SNAPSHOT_FORMAT_PNG; } -// static -LLSpinCtrl* LLFloaterOutfitSnapshot::Impl::getWidthSpinner(LLFloaterOutfitSnapshot* floater) -{ - LLPanelSnapshot* active_panel = getActivePanel(floater); - return active_panel ? active_panel->getWidthSpinner() : floater->getChild("snapshot_width"); -} - -// static -LLSpinCtrl* LLFloaterOutfitSnapshot::Impl::getHeightSpinner(LLFloaterOutfitSnapshot* floater) -{ - LLPanelSnapshot* active_panel = getActivePanel(floater); - return active_panel ? active_panel->getHeightSpinner() : floater->getChild("snapshot_height"); -} - -// static -void LLFloaterOutfitSnapshot::Impl::enableAspectRatioCheckbox(LLFloaterOutfitSnapshot* floater, BOOL enable) -{ - LLPanelSnapshot* active_panel = getActivePanel(floater); - if (active_panel) - { - active_panel->enableAspectRatioCheckbox(enable); - } -} - -// static -void LLFloaterOutfitSnapshot::Impl::setAspectRatioCheckboxValue(LLFloaterOutfitSnapshot* floater, BOOL checked) -{ - LLPanelSnapshot* active_panel = getActivePanel(floater); - if (active_panel) - { - active_panel->getChild(active_panel->getAspectRatioCBName())->setValue(checked); - } -} - // static LLSnapshotLivePreview* LLFloaterOutfitSnapshot::Impl::getPreviewView(LLFloaterOutfitSnapshot *floater) { @@ -248,14 +175,7 @@ LLSnapshotLivePreview* LLFloaterOutfitSnapshot::Impl::getPreviewView(LLFloaterOu // static LLViewerWindow::ESnapshotType LLFloaterOutfitSnapshot::Impl::getLayerType(LLFloaterOutfitSnapshot* floater) { - LLViewerWindow::ESnapshotType type = LLViewerWindow::SNAPSHOT_TYPE_COLOR; - LLSD value = floater->getChild("layer_types")->getValue(); - const std::string id = value.asString(); - if (id == "colors") - type = LLViewerWindow::SNAPSHOT_TYPE_COLOR; - else if (id == "depth") - type = LLViewerWindow::SNAPSHOT_TYPE_DEPTH; - return type; + return LLViewerWindow::SNAPSHOT_TYPE_COLOR; } // static @@ -375,67 +295,9 @@ void LLFloaterOutfitSnapshot::Impl::updateControls(LLFloaterOutfitSnapshot* floa { LLPanelSnapshot::ESnapshotType shot_type = getActiveSnapshotType(floater); LLFloaterSnapshotBase::ESnapshotFormat shot_format = (LLFloaterSnapshotBase::ESnapshotFormat)gSavedSettings.getS32("SnapshotFormat"); - LLViewerWindow::ESnapshotType layer_type = getLayerType(floater); - - floater->getChild("local_format_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFormat")); - floater->getChildView("layer_types")->setEnabled(shot_type == LLPanelSnapshot::SNAPSHOT_LOCAL); - - LLPanelSnapshot* active_panel = getActivePanel(floater); - if (active_panel) - { - LLSpinCtrl* width_ctrl = getWidthSpinner(floater); - LLSpinCtrl* height_ctrl = getHeightSpinner(floater); - - // Initialize spinners. - if (width_ctrl->getValue().asInteger() == 0) - { - S32 w = gViewerWindow->getWindowWidthRaw(); - LL_DEBUGS() << "Initializing width spinner (" << width_ctrl->getName() << "): " << w << LL_ENDL; - width_ctrl->setValue(w); - if (getActiveSnapshotType(floater) == LLPanelSnapshot::SNAPSHOT_TEXTURE) - { - width_ctrl->setIncrement(w >> 1); - } - } - if (height_ctrl->getValue().asInteger() == 0) - { - S32 h = gViewerWindow->getWindowHeightRaw(); - LL_DEBUGS() << "Initializing height spinner (" << height_ctrl->getName() << "): " << h << LL_ENDL; - height_ctrl->setValue(h); - if (getActiveSnapshotType(floater) == LLPanelSnapshot::SNAPSHOT_TEXTURE) - { - height_ctrl->setIncrement(h >> 1); - } - } - - // Clamp snapshot resolution to window size when showing UI or HUD in snapshot. - if (gSavedSettings.getBOOL("RenderUIInSnapshot") || gSavedSettings.getBOOL("RenderHUDInSnapshot")) - { - S32 width = gViewerWindow->getWindowWidthRaw(); - S32 height = gViewerWindow->getWindowHeightRaw(); - - width_ctrl->setMaxValue(width); - - height_ctrl->setMaxValue(height); - - if (width_ctrl->getValue().asInteger() > width) - { - width_ctrl->forceSetValue(width); - } - if (height_ctrl->getValue().asInteger() > height) - { - height_ctrl->forceSetValue(height); - } - } - else - { - width_ctrl->setMaxValue(6016); - height_ctrl->setMaxValue(6016); - } - } + LLViewerWindow::ESnapshotType layer_type = getLayerType(floater); LLSnapshotLivePreview* previewp = getPreviewView(floater); - BOOL got_bytes = previewp && previewp->getDataSize() > 0; BOOL got_snap = previewp && previewp->getSnapshotUpToDate(); // *TODO: Separate maximum size for Web images from postcards @@ -458,36 +320,9 @@ void LLFloaterOutfitSnapshot::Impl::updateControls(LLFloaterOutfitSnapshot* floa } floater->getChild("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : floater->getString("unknown")); - floater->getChild("file_size_label")->setColor( - shot_type == LLPanelSnapshot::SNAPSHOT_POSTCARD - && got_bytes - && previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" )); - - // Update the width and height spinners based on the corresponding resolution combos. (?) - switch(shot_type) - { - case LLPanelSnapshot::SNAPSHOT_WEB: - layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR; - floater->getChild("layer_types")->setValue("colors"); - setResolution(floater, "profile_size_combo"); - break; - case LLPanelSnapshot::SNAPSHOT_POSTCARD: - layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR; - floater->getChild("layer_types")->setValue("colors"); - setResolution(floater, "postcard_size_combo"); - break; - case LLPanelSnapshot::SNAPSHOT_TEXTURE: - layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR; - floater->getChild("layer_types")->setValue("colors"); - setResolution(floater, "texture_size_combo"); - break; - case LLPanelSnapshot::SNAPSHOT_LOCAL: - setResolution(floater, "local_size_combo"); - break; - default: - break; - } - setAspectRatioCheckboxValue(floater, !floater->impl.mAspectRatioCheckOff && gSavedSettings.getBOOL("KeepAspectForSnapshot")); + floater->getChild("file_size_label")->setColor(LLUIColorTable::instance().getColor( "LabelTextColor" )); + + setResolution(floater, "texture_size_combo"); if (previewp) { @@ -641,32 +476,6 @@ void LLFloaterOutfitSnapshot::Impl::onClickHUDCheck(LLUICtrl *ctrl, void* data) // static void LLFloaterOutfitSnapshot::Impl::applyKeepAspectCheck(LLFloaterOutfitSnapshot* view, BOOL checked) { - gSavedSettings.setBOOL("KeepAspectForSnapshot", checked); - - if (view) - { - LLPanelSnapshot* active_panel = getActivePanel(view); - if (checked && active_panel) - { - LLComboBox* combo = view->getChild(active_panel->getImageSizeComboName()); - combo->setCurrentByIndex(combo->getItemCount() - 1); // "custom" is always the last index - } - - LLSnapshotLivePreview* previewp = getPreviewView(view) ; - if(previewp) - { - previewp->mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ; - - S32 w, h ; - previewp->getSize(w, h) ; - updateSpinners(view, previewp, w, h, TRUE); // may change w and h - - LL_DEBUGS() << "updating thumbnail" << LL_ENDL; - previewp->setSize(w, h) ; - previewp->updateSnapshot(TRUE); - checkAutoSnapshot(previewp, TRUE); - } - } } // static @@ -691,44 +500,6 @@ void LLFloaterOutfitSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* da updateLayout(view); } -// static -void LLFloaterOutfitSnapshot::Impl::checkAspectRatio(LLFloaterOutfitSnapshot *view, S32 index) -{ - LLSnapshotLivePreview *previewp = getPreviewView(view) ; - - // Don't round texture sizes; textures are commonly stretched in world, profiles, etc and need to be "squashed" during upload, not cropped here - if(LLPanelSnapshot::SNAPSHOT_TEXTURE == getActiveSnapshotType(view)) - { - previewp->mKeepAspectRatio = FALSE ; - return ; - } - - BOOL keep_aspect = FALSE, enable_cb = FALSE; - - if (0 == index) // current window size - { - enable_cb = FALSE; - keep_aspect = TRUE; - } - else if (-1 == index) // custom - { - enable_cb = TRUE; - keep_aspect = gSavedSettings.getBOOL("KeepAspectForSnapshot"); - } - else // predefined resolution - { - enable_cb = FALSE; - keep_aspect = FALSE; - } - - view->impl.mAspectRatioCheckOff = !enable_cb; - - if (previewp) - { - previewp->mKeepAspectRatio = keep_aspect; - } -} - // Show/hide upload progress indicators. // static void LLFloaterOutfitSnapshot::Impl::setWorking(LLFloaterOutfitSnapshot* floater, bool working) @@ -807,78 +578,22 @@ void LLFloaterOutfitSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, width = llmin(width, gViewerWindow->getWindowWidthRaw()); height = llmin(height, gViewerWindow->getWindowHeightRaw()); } + - if (width == 0 || height == 0) - { - // take resolution from current window size - LL_DEBUGS() << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << LL_ENDL; - previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); - } - else if (width == -1 || height == -1) - { - // load last custom value - S32 new_width = 0, new_height = 0; - LLPanelSnapshot* spanel = getActivePanel(view); - if (spanel) - { - LL_DEBUGS() << "Loading typed res from panel " << spanel->getName() << LL_ENDL; - new_width = spanel->getTypedPreviewWidth(); - new_height = spanel->getTypedPreviewHeight(); - - // Limit custom size for inventory snapshots to 512x512 px. - if (getActiveSnapshotType(view) == LLPanelSnapshot::SNAPSHOT_TEXTURE) - { - new_width = llmin(new_width, MAX_TEXTURE_SIZE); - new_height = llmin(new_height, MAX_TEXTURE_SIZE); - } - } - else - { - LL_DEBUGS() << "No custom res chosen, setting preview res from window: " - << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << LL_ENDL; - new_width = gViewerWindow->getWindowWidthRaw(); - new_height = gViewerWindow->getWindowHeightRaw(); - } + llassert(width > 0 && height > 0); - llassert(new_width > 0 && new_height > 0); - previewp->setSize(new_width, new_height); - } - else - { - // use the resolution from the selected pre-canned drop-down choice - LL_DEBUGS() << "Setting preview res selected from combo: " << width << "x" << height << LL_ENDL; - previewp->setSize(width, height); - } - - checkAspectRatio(view, width) ; - - previewp->getSize(width, height); - - // We use the height spinner here because we come here via the aspect ratio - // checkbox as well and we want height always changing to width by default. - // If we use the width spinner we would change width according to height by - // default, that is not what we want. - updateSpinners(view, previewp, width, height, !getHeightSpinner(view)->isDirty()); // may change width and height + // use the resolution from the selected pre-canned drop-down choice + LL_DEBUGS() << "Setting preview res selected from combo: " << width << "x" << height << LL_ENDL; + previewp->setSize(width, height); - if(getWidthSpinner(view)->getValue().asInteger() != width || getHeightSpinner(view)->getValue().asInteger() != height) - { - getWidthSpinner(view)->setValue(width); - getHeightSpinner(view)->setValue(height); - if (getActiveSnapshotType(view) == LLPanelSnapshot::SNAPSHOT_TEXTURE) - { - getWidthSpinner(view)->setIncrement(width >> 1); - getHeightSpinner(view)->setIncrement(height >> 1); - } - } - if(original_width != width || original_height != height) { - previewp->setSize(width, height); + //previewp->setSize(width, height); // hide old preview as the aspect ratio could be wrong checkAutoSnapshot(previewp, FALSE); LL_DEBUGS() << "updating thumbnail" << LL_ENDL; - getPreviewView(view)->updateSnapshot(TRUE); + previewp->updateSnapshot(TRUE); if(do_update) { LL_DEBUGS() << "Will update controls" << LL_ENDL; @@ -928,15 +643,6 @@ void LLFloaterOutfitSnapshot::Impl::onImageFormatChange(LLFloaterOutfitSnapshot* } } -// Sets the named size combo to "custom" mode. -// static -void LLFloaterOutfitSnapshot::Impl::comboSetCustom(LLFloaterOutfitSnapshot* floater, const std::string& comboname) -{ - LLComboBox* combo = floater->getChild(comboname); - combo->setCurrentByIndex(combo->getItemCount() - 1); // "custom" is always the last index - checkAspectRatio(floater, -1); // -1 means custom -} - // Update supplied width and height according to the constrain proportions flag; limit them by max_val. //static BOOL LLFloaterOutfitSnapshot::Impl::checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL isWidthChanged, S32 max_value) @@ -983,58 +689,6 @@ BOOL LLFloaterOutfitSnapshot::Impl::checkImageSize(LLSnapshotLivePreview* previe return (w != width || h != height) ; } -//static -void LLFloaterOutfitSnapshot::Impl::setImageSizeSpinnersValues(LLFloaterOutfitSnapshot *view, S32 width, S32 height) -{ - getWidthSpinner(view)->forceSetValue(width); - getHeightSpinner(view)->forceSetValue(height); - if (getActiveSnapshotType(view) == LLPanelSnapshot::SNAPSHOT_TEXTURE) - { - getWidthSpinner(view)->setIncrement(width >> 1); - getHeightSpinner(view)->setIncrement(height >> 1); - } -} - -// static -void LLFloaterOutfitSnapshot::Impl::updateSpinners(LLFloaterOutfitSnapshot* view, LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL is_width_changed) -{ - getWidthSpinner(view)->resetDirty(); - getHeightSpinner(view)->resetDirty(); - if (checkImageSize(previewp, width, height, is_width_changed, previewp->getMaxImageSize())) - { - setImageSizeSpinnersValues(view, width, height); - } -} - -// static -void LLFloaterOutfitSnapshot::Impl::applyCustomResolution(LLFloaterOutfitSnapshot* view, S32 w, S32 h) -{ - LL_DEBUGS() << "applyCustomResolution(" << w << ", " << h << ")" << LL_ENDL; - if (!view) return; - - LLSnapshotLivePreview* previewp = getPreviewView(view); - if (previewp) - { - S32 curw,curh; - previewp->getSize(curw, curh); - - if (w != curw || h != curh) - { - //if to upload a snapshot, process spinner input in a special way. - previewp->setMaxImageSize((S32) getWidthSpinner(view)->getMaxValue()) ; - - previewp->setSize(w,h); - checkAutoSnapshot(previewp, FALSE); - comboSetCustom(view, "profile_size_combo"); - comboSetCustom(view, "postcard_size_combo"); - comboSetCustom(view, "texture_size_combo"); - comboSetCustom(view, "local_size_combo"); - LL_DEBUGS() << "applied custom resolution, updating thumbnail" << LL_ENDL; - previewp->updateSnapshot(TRUE); - } - } -} - // static void LLFloaterOutfitSnapshot::Impl::onSnapshotUploadFinished(bool status) { @@ -1096,12 +750,6 @@ BOOL LLFloaterOutfitSnapshot::postBuild() childSetCommitCallback("hud_check", Impl::onClickHUDCheck, this); getChild("hud_check")->setValue(gSavedSettings.getBOOL("RenderHUDInSnapshot")); - impl.setAspectRatioCheckboxValue(this, gSavedSettings.getBOOL("KeepAspectForSnapshot")); - - childSetCommitCallback("layer_types", Impl::onCommitLayerTypes, this); - getChild("layer_types")->setValue("colors"); - getChildView("layer_types")->setEnabled(FALSE); - getChild("freeze_frame_check")->setValue(gSavedSettings.getBOOL("UseFreezeFrame")); childSetCommitCallback("freeze_frame_check", Impl::onCommitFreezeFrame, this); @@ -1261,7 +909,7 @@ S32 LLFloaterOutfitSnapshot::notify(const LLSD& info) impl.updateResolution(getChild(combo_name), this); return 1; } - + /* if (info.has("custom-res-change")) { LLSD res = info["custom-res-change"]; @@ -1274,7 +922,7 @@ S32 LLFloaterOutfitSnapshot::notify(const LLSD& info) impl.applyKeepAspectCheck(this, info["keep-aspect-change"].asBoolean()); return 1; } - + */ if (info.has("image-quality-change")) { impl.onImageQualityChange(this, info["image-quality-change"].asInteger()); diff --git a/indra/newview/llfloateroutfitsnapshot.h b/indra/newview/llfloateroutfitsnapshot.h index 176a9520c2..9982676bea 100644 --- a/indra/newview/llfloateroutfitsnapshot.h +++ b/indra/newview/llfloateroutfitsnapshot.h @@ -38,12 +38,6 @@ class LLFloaterOutfitSnapshot : public LLFloaterSnapshotBase LOG_CLASS(LLFloaterOutfitSnapshot); public: - //typedef enum e_snapshot_format - //{ - // SNAPSHOT_FORMAT_PNG, - // SNAPSHOT_FORMAT_JPEG, - // SNAPSHOT_FORMAT_BMP - //} ESnapshotFormat; LLFloaterOutfitSnapshot(const LLSD& key); virtual ~LLFloaterOutfitSnapshot(); diff --git a/indra/newview/llpanelsnapshot.cpp b/indra/newview/llpanelsnapshot.cpp index ca62f2bdf5..284f7aad3f 100755 --- a/indra/newview/llpanelsnapshot.cpp +++ b/indra/newview/llpanelsnapshot.cpp @@ -54,10 +54,18 @@ S32 power_of_two(S32 sz, S32 upper) BOOL LLPanelSnapshot::postBuild() { getChild(getImageSizeComboName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onResolutionComboCommit, this, _1)); - getChild(getWidthSpinnerName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onCustomResolutionCommit, this)); - getChild(getHeightSpinnerName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onCustomResolutionCommit, this)); - getChild(getAspectRatioCBName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onKeepAspectRatioCommit, this, _1)); - + if (!getWidthSpinnerName().empty()) + { + getChild(getWidthSpinnerName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onCustomResolutionCommit, this)); + } + if (!getHeightSpinnerName().empty()) + { + getChild(getHeightSpinnerName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onCustomResolutionCommit, this)); + } + if (!getAspectRatioCBName().empty()) + { + getChild(getAspectRatioCBName())->setCommitCallback(boost::bind(&LLPanelSnapshot::onKeepAspectRatioCommit, this, _1)); + } updateControls(LLSD()); return TRUE; } @@ -92,27 +100,32 @@ void LLPanelSnapshot::enableControls(BOOL enable) LLSpinCtrl* LLPanelSnapshot::getWidthSpinner() { + llassert(!getWidthSpinnerName().empty()); return getChild(getWidthSpinnerName()); } LLSpinCtrl* LLPanelSnapshot::getHeightSpinner() { + llassert(!getHeightSpinnerName().empty()); return getChild(getHeightSpinnerName()); } S32 LLPanelSnapshot::getTypedPreviewWidth() const { + llassert(!getWidthSpinnerName().empty()); return getChild(getWidthSpinnerName())->getValue().asInteger(); } S32 LLPanelSnapshot::getTypedPreviewHeight() const { - return getChild(getHeightSpinnerName())->getValue().asInteger(); + llassert(!getHeightSpinnerName().empty()); + return getChild(getHeightSpinnerName())->getValue().asInteger(); } void LLPanelSnapshot::enableAspectRatioCheckbox(BOOL enable) { - getChild(getAspectRatioCBName())->setEnabled(enable); + llassert(!getAspectRatioCBName().empty()); + getChild(getAspectRatioCBName())->setEnabled(enable); } LLSideTrayPanelContainer* LLPanelSnapshot::getParentContainer() @@ -177,9 +190,11 @@ void LLPanelSnapshot::cancel() void LLPanelSnapshot::onCustomResolutionCommit() { LLSD info; - LLSpinCtrl *widthSpinner = getChild(getWidthSpinnerName()); - LLSpinCtrl *heightSpinner = getChild(getHeightSpinnerName()); - //TODO: Refactoring - move this code into some virtual method of LLPanelSnapshotInventory + std::string widthSpinnerName = getWidthSpinnerName(); + std::string heightSpinnerName = getHeightSpinnerName(); + llassert(!widthSpinnerName.empty() && !heightSpinnerName.empty()); + LLSpinCtrl *widthSpinner = getChild(widthSpinnerName); + LLSpinCtrl *heightSpinner = getChild(heightSpinnerName); if (getName() == "panel_snapshot_inventory") { S32 width = widthSpinner->getValue().asInteger(); diff --git a/indra/newview/llpanelsnapshot.h b/indra/newview/llpanelsnapshot.h index d64ef3b75a..3868020cdf 100755 --- a/indra/newview/llpanelsnapshot.h +++ b/indra/newview/llpanelsnapshot.h @@ -68,7 +68,7 @@ protected: LLSideTrayPanelContainer* getParentContainer(); void updateImageQualityLevel(); void goBack(); ///< Switch to the default (Snapshot Options) panel - void cancel(); + virtual void cancel(); // common UI callbacks void onCustomResolutionCommit(); diff --git a/indra/newview/llpanelsnapshotinventory.cpp b/indra/newview/llpanelsnapshotinventory.cpp index 013a564908..057e046e30 100755 --- a/indra/newview/llpanelsnapshotinventory.cpp +++ b/indra/newview/llpanelsnapshotinventory.cpp @@ -47,19 +47,6 @@ class LLPanelSnapshotInventoryBase public: LLPanelSnapshotInventoryBase(); -// -// /*virtual*/ BOOL postBuild(); -// /*virtual*/ void onOpen(const LLSD& key); -// -// void onResolutionCommit(LLUICtrl* ctrl); -// -//private: -// /*virtual*/ std::string getWidthSpinnerName() const { return "inventory_snapshot_width"; } -// /*virtual*/ std::string getHeightSpinnerName() const { return "inventory_snapshot_height"; } -// /*virtual*/ std::string getAspectRatioCBName() const { return "inventory_keep_aspect_check"; } -// /*virtual*/ std::string getImageSizeComboName() const { return "texture_size_combo"; } -// /*virtual*/ std::string getImageSizePanelName() const { return LLStringUtil::null; } -// /*virtual*/ void updateControls(const LLSD& info); protected: virtual void onSend() = 0; @@ -99,18 +86,17 @@ public: LLPanelOutfitSnapshotInventory(); /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); - - void onResolutionCommit(LLUICtrl* ctrl); - - private: - /*virtual*/ std::string getWidthSpinnerName() const { return "inventory_snapshot_width"; } - /*virtual*/ std::string getHeightSpinnerName() const { return "inventory_snapshot_height"; } - /*virtual*/ std::string getAspectRatioCBName() const { return "inventory_keep_aspect_check"; } - /*virtual*/ std::string getImageSizeComboName() const { return "texture_size_combo"; } - /*virtual*/ std::string getImageSizePanelName() const { return LLStringUtil::null; } - /*virtual*/ void updateControls(const LLSD& info); + +private: + /*virtual*/ std::string getWidthSpinnerName() const { return ""; } + /*virtual*/ std::string getHeightSpinnerName() const { return ""; } + /*virtual*/ std::string getAspectRatioCBName() const { return ""; } + /*virtual*/ std::string getImageSizeComboName() const { return "texture_size_combo"; } + /*virtual*/ std::string getImageSizePanelName() const { return LLStringUtil::null; } + /*virtual*/ void updateControls(const LLSD& info); /*virtual*/ void onSend(); + /*virtual*/ void cancel(); }; static LLPanelInjector panel_class1("llpanelsnapshotinventory"); @@ -172,16 +158,12 @@ void LLPanelSnapshotInventory::onSend() LLPanelOutfitSnapshotInventory::LLPanelOutfitSnapshotInventory() { mCommitCallbackRegistrar.add("Inventory.SaveOutfitPhoto", boost::bind(&LLPanelOutfitSnapshotInventory::onSend, this)); - mCommitCallbackRegistrar.add("Inventory.Cancel", boost::bind(&LLPanelOutfitSnapshotInventory::cancel, this)); + mCommitCallbackRegistrar.add("Inventory.SaveOutfitCancel", boost::bind(&LLPanelOutfitSnapshotInventory::cancel, this)); } // virtual BOOL LLPanelOutfitSnapshotInventory::postBuild() { - getChild(getWidthSpinnerName())->setAllowEdit(FALSE); - getChild(getHeightSpinnerName())->setAllowEdit(FALSE); - - getChild(getImageSizeComboName())->setCommitCallback(boost::bind(&LLPanelOutfitSnapshotInventory::onResolutionCommit, this, _1)); return LLPanelSnapshot::postBuild(); } @@ -199,15 +181,13 @@ void LLPanelOutfitSnapshotInventory::updateControls(const LLSD& info) getChild("save_btn")->setEnabled(have_snapshot); } -void LLPanelOutfitSnapshotInventory::onResolutionCommit(LLUICtrl* ctrl) -{ - BOOL current_window_selected = (getChild(getImageSizeComboName())->getCurrentIndex() == 3); - getChild(getWidthSpinnerName())->setVisible(!current_window_selected); - getChild(getHeightSpinnerName())->setVisible(!current_window_selected); -} - void LLPanelOutfitSnapshotInventory::onSend() { LLFloaterOutfitSnapshot::saveTexture(); LLFloaterOutfitSnapshot::postSave(); } + +void LLPanelOutfitSnapshotInventory::cancel() +{ + getParentByType()->closeFloater(); +} diff --git a/indra/newview/skins/default/xui/en/floater_outfit_snapshot.xml b/indra/newview/skins/default/xui/en/floater_outfit_snapshot.xml index 7b88b07ca6..34f02e535f 100644 --- a/indra/newview/skins/default/xui/en/floater_outfit_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_outfit_snapshot.xml @@ -156,23 +156,6 @@ width="100"> Capture: - - - - - - - - - - - - - Saving an image to your inventory costs L$[UPLOAD_COST]. To save your image as a texture select one of the square formats. + Uploading an image to your inventory costs L$[UPLOAD_COST].