summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorpavelkproductengine <pavelkproductengine@lindenlab.com>2015-12-11 19:58:08 +0200
committerpavelkproductengine <pavelkproductengine@lindenlab.com>2015-12-11 19:58:08 +0200
commit6a02f5bbcec2b1a530ceeacb0dc564cfeb7cbc7f (patch)
tree0a811059e4982105c4fb506241b94e61602fb8e4 /indra
parent1be63209331d509396bd7ee79302d511fe83d72e (diff)
Initial version of Visual Outfit Browser
Diffstat (limited to 'indra')
-rwxr-xr-xindra/llui/llfocusmgr.cpp1
-rwxr-xr-xindra/llui/lllayoutstack.cpp2
-rwxr-xr-xindra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/lloutfitgallery.cpp699
-rw-r--r--indra/newview/lloutfitgallery.h152
-rwxr-xr-xindra/newview/lloutfitslist.cpp1234
-rwxr-xr-xindra/newview/lloutfitslist.h204
-rwxr-xr-xindra/newview/llpaneloutfitsinventory.cpp6
-rwxr-xr-xindra/newview/llpaneloutfitsinventory.h4
-rwxr-xr-xindra/newview/lltexturectrl.cpp2
-rwxr-xr-xindra/newview/skins/default/textures/textures.xml1
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_snapshot.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_outfit_gear.xml16
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfit_gallery.xml128
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml49
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_outfits_inventory.xml11
16 files changed, 2022 insertions, 493 deletions
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 <boost/foreach.hpp>
+
+// llcommon
+#include "llcommonutils.h"
+#include "llvfile.h"
+
+#include "llappearancemgr.h"
+#include "lleconomy.h"
+#include "llerror.h"
+#include "llfilepicker.h"
+#include "llfloaterperms.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "lllocalbitmaps.h"
+#include "llviewermenufile.h"
+#include "llwearableitemslist.h"
+
+
+static LLPanelInjector<LLOutfitGallery> t_outfit_gallery("outfit_gallery");
+static LLOutfitGallery* gOutfitGallery = NULL;
+
+LLOutfitGallery::LLOutfitGallery()
+ : LLOutfitListBase(),
+ mTexturesObserver(NULL)
+{
+// 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<LLPanel>("gallery_panel")->getChildList());
+ BOOST_FOREACH(LLView* view, child_list)
+ {
+ LLLayoutStack* lstack = dynamic_cast<LLLayoutStack*>(view);
+ if (lstack != NULL)
+ {
+ LLView::child_list_t panel_list(*lstack->getChildList());
+ BOOST_FOREACH(LLView* panel, panel_list)
+ {
+ //LLLayoutPanel* lpanel = dynamic_cast<LLLayoutPanel*>(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<LLOutfitGalleryItem*>(view_item);
+ if (gallery_item != NULL)
+ panel->removeChild(gallery_item);
+ }
+ lstack->removeChild(panel);
+ //delete panel;
+ }
+ getChild<LLPanel>("gallery_panel")->removeChild(lstack);
+ delete lstack;
+ }
+ else
+ {
+ getChild<LLPanel>("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<LLPanel>("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<LLPanel>("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<LLOutfitGalleryItem>(giparams);
+ LLRect girect = LLRect(0, GALLERY_ITEM_HEIGHT - GALLERY_ITEM_HEIGHT,
+ GALLERY_ITEM_WIDTH, 0);
+ //gitem->setRect(girect);
+ gitem->reshape(GALLERY_ITEM_WIDTH, GALLERY_ITEM_HEIGHT);
+ gitem->setVisible(true);
+ gitem->setFollowsLeft();
+ gitem->setFollowsTop();
+ gitem->setOutfitName(name);
+ return gitem;
+}
+
+LLLayoutPanel* LLOutfitGallery::buildLayoutPanel(int left)
+{
+ LLLayoutPanel::Params lpparams;
+ int top = 0;
+ LLLayoutPanel* lpanel = LLUICtrlFactory::create<LLLayoutPanel>(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<LLLayoutStack>(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<LLOutfitGalleryItem> 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<LLTextBox>("outfit_name");
+ mOutfitWornText = getChild<LLTextBox>("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<LLOutfitGallery*>(mOutfitList);
+ if (gallery && selected_outfit_id.notNull())
+ {
+ gallery->uploadPhoto(selected_outfit_id);
+ }
+ if (selected_outfit_id.notNull())
+ {
+
+ }
+}
+
+void LLOutfitGalleryGearMenu::onLoadAssets()
+{
+ LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
+ if (gallery != NULL)
+ {
+ gallery->loadPhotos();
+ }
+}
+
+void LLOutfitGallery::loadPhotos()
+{
+ //Iterate over inventory
+ LLUUID textures = gInventory.findCategoryUUIDForType(LLFolderType::EType::FT_TEXTURE);
+ LLViewerInventoryCategory* category = gInventory.getCategory(textures);
+ if (!category)
+ return;
+
+ if (mTexturesObserver == NULL)
+ {
+ mTexturesObserver = new LLInventoryCategoriesObserver();
+ gInventory.addObserver(mTexturesObserver);
+ }
+
+ // Start observing changes in "My Outfits" category.
+ mTexturesObserver->addCategory(textures,
+ boost::bind(&LLOutfitGallery::refreshTextures, this, textures));
+
+ category->fetch();
+ refreshTextures(textures);
+}
+
+void LLOutfitGallery::refreshTextures(const LLUUID& category_id)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ // Collect all sub-categories of a given category.
+ LLIsType is_texture(LLAssetType::AT_TEXTURE);
+ gInventory.collectDescendentsIf(
+ category_id,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_texture);
+
+ //Find textures which contain outfit UUID string in description
+ LLInventoryModel::item_array_t uploaded_item_array;
+ BOOST_FOREACH(LLViewerInventoryItem* item, item_array)
+ {
+ std::string desc = item->getDescription();
+
+ LLUUID outfit_id(desc);
+
+ //Check whether description contains correct UUID of outfit
+ if (outfit_id.isNull())
+ continue;
+
+ outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id);
+ if (outfit_it != mOutfitMap.end() && !outfit_it->first.isNull())
+ {
+ uploaded_item_array.push_back(item);
+ }
+ }
+
+ uuid_vec_t vadded;
+ uuid_vec_t vremoved;
+
+ // Create added and removed items vectors.
+ computeDifferenceOfTextures(uploaded_item_array, vadded, vremoved);
+
+ BOOST_FOREACH(LLUUID item_id, vadded)
+ {
+ LLViewerInventoryItem* added_item = gInventory.getItem(item_id);
+ LLUUID asset_id = added_item->getAssetUUID();
+ std::string desc = added_item->getDescription();
+ LLUUID outfit_id(desc);
+ mOutfitMap[outfit_id]->setImageAssetId(asset_id);
+ mTextureMap[outfit_id] = added_item;
+ }
+
+ BOOST_FOREACH(LLUUID item_id, vremoved)
+ {
+ LLViewerInventoryItem* rm_item = gInventory.getItem(item_id);
+ std::string desc = rm_item->getDescription();
+ LLUUID outfit_id(desc);
+ mOutfitMap[outfit_id]->setDefaultImage();
+ mTextureMap.erase(outfit_id);
+ }
+
+ /*
+ LLInventoryModel::item_array_t::const_iterator it = item_array.begin();
+ for ( ; it != item_array.end(); it++)
+ {
+ LLViewerInventoryItem* item = (*it);
+ LLUUID asset_id = item->getAssetUUID();
+
+ std::string desc = item->getDescription();
+
+ LLUUID outfit_id(desc);
+
+ //Check whether description contains correct UUID of outfit
+ if (outfit_id.isNull())
+ continue;
+
+ outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id);
+ if (outfit_it != mOutfitMap.end() && !outfit_it->first.isNull())
+ {
+ outfit_it->second->setImageAssetId(asset_id);
+ mTextureMap[outfit_id] = item;
+ }
+
+
+ //LLUUID* item_idp = new LLUUID();
+
+ //gOutfitGallery = this;
+ //const BOOL high_priority = TRUE;
+ //gAssetStorage->getAssetData(asset_id,
+ // LLAssetType::AT_TEXTURE,
+ // onLoadComplete,
+ // (void**)item_idp,
+ // high_priority);
+ //
+ ////mAssetStatus = PREVIEW_ASSET_LOADING;
+
+ }
+ */
+}
+
+void LLOutfitGallery::onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status)
+{
+ LL_WARNS() << "asset_uuid: " << asset_uuid.asString() << LL_ENDL;
+
+ LLUUID* outfit_id = (LLUUID*)user_data;
+ if (!user_data)
+ return;
+ LL_WARNS() << "outfit_id: " << outfit_id->asString() << LL_ENDL;
+
+ outfit_map_t::iterator it = gOutfitGallery->mOutfitMap.find(*outfit_id);
+ if (it != gOutfitGallery->mOutfitMap.end() && !it->first.isNull())
+ {
+ }
+}
+
+void LLOutfitGallery::uploadPhoto(LLUUID outfit_id)
+{
+ outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id);
+ if (outfit_it == mOutfitMap.end() || outfit_it->first.isNull())
+ {
+ return;
+ }
+
+ bool add_successful = false;
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE))
+ {
+ std::string filename = picker.getFirstFile();
+ LLLocalBitmap* unit = new LLLocalBitmap(filename);
+ if (unit->getValid())
+ {
+ add_successful = true;
+ LLAssetStorage::LLStoreAssetCallback callback = NULL;
+ S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); // kinda hack - assumes that unsubclassed LLFloaterNameDesc is only used for uploading chargeable assets, which it is right now (it's only used unsubclassed for the sound upload dialog, and THAT should be a subclass).
+ void *nruserdata = NULL;
+ nruserdata = (void *)&outfit_id;
+
+ LL_WARNS() << "selected_outfit_id: " << outfit_id.asString() << LL_ENDL;
+
+ //LLViewerInventoryItem *outfit = gInventory.getItem(selected_outfit_id);
+ LLViewerInventoryCategory *outfit_cat = gInventory.getCategory(outfit_id);
+ if (!outfit_cat) return;
+
+ checkRemovePhoto(outfit_id);
+
+ LLStringUtil::format_map_t foto_string_args;
+ foto_string_args["OUTFIT_NAME"] = outfit_cat->getName();
+ std::string display_name = getString("outfit_foto_string", foto_string_args);
+
+ upload_new_resource(filename, // file
+ display_name,
+ outfit_id.asString(),
+ 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ display_name, callback, expected_upload_cost, nruserdata);
+ }
+ }
+}
+
+bool LLOutfitGallery::checkRemovePhoto(LLUUID outfit_id)
+{
+ //remove existing photo of outfit from inventory
+ texture_map_t::iterator texture_it = mTextureMap.find(outfit_id);
+ if (texture_it != mTextureMap.end()) {
+ gInventory.removeItem(texture_it->second->getUUID());
+ return true;
+ }
+ return false;
+}
+
+void LLOutfitGallery::setUploadedPhoto(LLUUID outfit_id, LLUUID asset_id)
+{
+
+}
+
+void LLOutfitGallery::computeDifferenceOfTextures(
+ const LLInventoryModel::item_array_t& vtextures,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved)
+{
+ uuid_vec_t vnew;
+ // Creating a vector of newly collected sub-categories UUIDs.
+ for (LLInventoryModel::item_array_t::const_iterator iter = vtextures.begin();
+ iter != vtextures.end();
+ iter++)
+ {
+ vnew.push_back((*iter)->getUUID());
+ }
+
+ uuid_vec_t vcur;
+ // Creating a vector of currently uploaded texture UUIDs.
+ for (texture_map_t::const_iterator iter = mTextureMap.begin();
+ iter != mTextureMap.end();
+ iter++)
+ {
+ vcur.push_back((*iter).second->getUUID());
+ }
+// getCurrentCategories(vcur);
+
+ LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
+
+}
diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h
new file mode 100644
index 0000000000..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 <vector>
+
+class LLVFS;
+class LLOutfitGalleryItem;
+class LLOutfitListGearMenuBase;
+class LLOutfitGalleryGearMenu;
+
+class LLOutfitGallery : public LLOutfitListBase
+{
+public:
+ friend class LLOutfitGalleryGearMenu;
+ LLOutfitGallery();
+ virtual ~LLOutfitGallery();
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void onOpen(const LLSD& info);
+
+ /*virtual*/ void setFilterSubString(const std::string& string);
+
+ /*virtual*/ void getCurrentCategories(uuid_vec_t& vcur);
+ /*virtual*/ void updateAddedCategory(LLUUID cat_id);
+ /*virtual*/ void updateRemovedCategory(LLUUID cat_id);
+ /*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name);
+
+ /*virtual*/ bool hasItemSelected();
+ /*virtual*/ bool canWearSelected();
+
+ /*virtual*/ bool getHasExpandableFolders() { return FALSE; }
+
+ void refreshTextures(const LLUUID& category_id);
+ void computeDifferenceOfTextures(const LLInventoryModel::item_array_t& vtextures, uuid_vec_t& vadded, uuid_vec_t& vremoved);
+
+protected:
+ /*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id);
+ /*virtual*/ void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid);
+ /*virtual*/ void onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
+ /*virtual*/ void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
+
+ /*virtual*/ void onCollapseAllFolders() {}
+ /*virtual*/ void onExpandAllFolders() {}
+ /*virtual*/ LLOutfitListGearMenuBase* createGearMenu();
+
+private:
+ void 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<LLLayoutStack*> mLayouts;
+ std::vector<LLLayoutPanel*> mPanels;
+ std::vector<LLOutfitGalleryItem*> mItems;
+
+ typedef std::map<LLUUID, LLOutfitGalleryItem*> outfit_map_t;
+ typedef outfit_map_t::value_type outfit_map_value_t;
+ outfit_map_t mOutfitMap;
+ typedef std::map<LLUUID, LLViewerInventoryItem*> texture_map_t;
+ typedef texture_map_t::value_type texture_map_value_t;
+ texture_map_t mTextureMap;
+
+ LLInventoryCategoriesObserver* mTexturesObserver;
+
+};
+
+//static LLOutfitGallery* gOutfitGallery;
+
+class LLOutfitGalleryGearMenu : public LLOutfitListGearMenuBase
+{
+public:
+ friend class LLOutfitGallery;
+ LLOutfitGalleryGearMenu(LLOutfitListBase* olist);
+
+protected:
+ /*virtual*/ void onUpdateItemsVisibility();
+
+private:
+ /*virtual*/ void onUploadFoto();
+ /*virtual*/ void onLoadAssets();
+};
+
+class LLOutfitGalleryItem : public LLPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLPanel::Params>
+ {};
+
+ LLOutfitGalleryItem(const Params& p);
+ virtual ~LLOutfitGalleryItem();
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void draw();
+ /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+
+ void setDefaultImage();
+ void setImageAssetId(LLUUID asset_id);
+ void setOutfitName(std::string name);
+ void setOutfitWorn(bool value);
+ void setSelected(bool value);
+private:
+ LLPointer<LLViewerTexture> mTexturep;
+ LLTextBox* mOutfitNameText;
+ LLTextBox* mOutfitWornText;
+};
+
+#endif // LL_LLOUTFITGALLERYCTRL_H
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 883221382c..736da5d411 100755
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -38,7 +38,7 @@
#include "llfloatersidepanelcontainer.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
-#include "lllistcontextmenu.h"
+//#include "lllistcontextmenu.h"
#include "llmenubutton.h"
#include "llnotificationsutil.h"
#include "lloutfitobserver.h"
@@ -98,339 +98,204 @@ const outfit_accordion_tab_params& get_accordion_tab_params()
}
-//////////////////////////////////////////////////////////////////////////
+static LLPanelInjector<LLOutfitsList> t_outfits_list("outfits_list");
-class LLOutfitListGearMenu
+LLOutfitsList::LLOutfitsList()
+ : LLOutfitListBase()
+ , mAccordion(NULL)
+ , mListCommands(NULL)
+ , mItemSelected(false)
{
-public:
- LLOutfitListGearMenu(LLOutfitsList* olist)
- : mOutfitList(olist),
- mMenu(NULL)
- {
- llassert_always(mOutfitList);
+// mCategoriesObserver = new LLInventoryCategoriesObserver();
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
- LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
-
- registrar.add("Gear.Wear", boost::bind(&LLOutfitListGearMenu::onWear, this));
- registrar.add("Gear.TakeOff", boost::bind(&LLOutfitListGearMenu::onTakeOff, this));
- registrar.add("Gear.Rename", boost::bind(&LLOutfitListGearMenu::onRename, this));
- registrar.add("Gear.Delete", boost::bind(&LLOutfitsList::removeSelected, mOutfitList));
- registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenu::onCreate, this, _2));
- registrar.add("Gear.Collapse", boost::bind(&LLOutfitsList::collapse_all_folders, mOutfitList));
- registrar.add("Gear.Expand", boost::bind(&LLOutfitsList::expand_all_folders, mOutfitList));
-
- registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenu::onAdd, this));
-
- enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenu::onEnable, this, _2));
- enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenu::onVisible, this, _2));
-
- mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
- "menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- llassert(mMenu);
- }
-
- void updateItemsVisibility()
- {
- if (!mMenu) return;
+// mGearMenu = new LLOutfitListGearMenu(this);
+}
- bool have_selection = getSelectedOutfitID().notNull();
- mMenu->setItemVisible("sepatator1", have_selection);
- mMenu->setItemVisible("sepatator2", have_selection);
- mMenu->arrangeAndClear(); // update menu height
- }
+LLOutfitsList::~LLOutfitsList()
+{
+// delete mGearMenu;
+}
- LLToggleableMenu* getMenu() { return mMenu; }
+BOOL LLOutfitsList::postBuild()
+{
+ mAccordion = getChild<LLAccordionCtrl>("outfits_accordion");
+ mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR);
-private:
- const LLUUID& getSelectedOutfitID()
- {
- return mOutfitList->getSelectedOutfitUUID();
- }
+ //LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
- LLViewerInventoryCategory* getSelectedOutfit()
- {
- const LLUUID& selected_outfit_id = getSelectedOutfitID();
- if (selected_outfit_id.isNull())
- {
- return NULL;
- }
+ //menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenu::updateItemsVisibility, mGearMenu));
+ //menu_gear_btn->setMenu(mGearMenu->getMenu());
- LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id);
- return cat;
- }
+ return LLOutfitListBase::postBuild();
+}
- void onWear()
- {
- LLViewerInventoryCategory* selected_outfit = getSelectedOutfit();
- if (selected_outfit)
- {
- LLAppearanceMgr::instance().wearInventoryCategory(
- selected_outfit, /*copy=*/ FALSE, /*append=*/ FALSE);
- }
- }
+//virtual
+void LLOutfitsList::onOpen(const LLSD& info)
+{
+ if (!mIsInitialized)
+ {
+ const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ // Start observing changes in Current Outfit category.
+ mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this));
+ }
- void onAdd()
- {
- const LLUUID& selected_id = getSelectedOutfitID();
+ LLOutfitListBase::onOpen(info);
- if (selected_id.notNull())
- {
- LLAppearanceMgr::getInstance()->addCategoryToCurrentOutfit(selected_id);
- }
- }
+ // if (!mIsInitialized)
+ //{
+ // // *TODO: I'm not sure is this check necessary but it never match while developing.
+ // if (!gInventory.isInventoryUsable())
+ // return;
- void onTakeOff()
- {
- // Take off selected outfit.
- const LLUUID& selected_outfit_id = getSelectedOutfitID();
- if (selected_outfit_id.notNull())
- {
- LLAppearanceMgr::instance().takeOffOutfit(selected_outfit_id);
- }
- }
+ // const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- void onRename()
- {
- const LLUUID& selected_outfit_id = getSelectedOutfitID();
- if (selected_outfit_id.notNull())
- {
- LLAppearanceMgr::instance().renameOutfit(selected_outfit_id);
- }
- }
+ // // *TODO: I'm not sure is this check necessary but it never match while developing.
+ // LLViewerInventoryCategory* category = gInventory.getCategory(outfits);
+ // if (!category)
+ // return;
- void onCreate(const LLSD& data)
- {
- LLWearableType::EType type = LLWearableType::typeNameToType(data.asString());
- if (type == LLWearableType::WT_NONE)
- {
- LL_WARNS() << "Invalid wearable type" << LL_ENDL;
- return;
- }
+ // gInventory.addObserver(mCategoriesObserver);
- LLAgentWearables::createWearable(type, true);
- }
+ // // Start observing changes in "My Outfits" category.
+ // mCategoriesObserver->addCategory(outfits,
+ // boost::bind(&LLOutfitsList::refreshList, this, outfits));
- bool onEnable(LLSD::String param)
- {
- // Handle the "Wear - Replace Current Outfit" menu option specially
- // because LLOutfitList::isActionEnabled() checks whether it's allowed
- // to wear selected outfit OR selected items, while we're only
- // interested in the outfit (STORM-183).
- if ("wear" == param)
- {
- return LLAppearanceMgr::instance().getCanReplaceCOF(mOutfitList->getSelectedOutfitUUID());
- }
+ // const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
- return mOutfitList->isActionEnabled(param);
- }
+ // // Start observing changes in Current Outfit category.
+ // mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this));
- bool onVisible(LLSD::String param)
- {
- const LLUUID& selected_outfit_id = getSelectedOutfitID();
- if (selected_outfit_id.isNull()) // no selection or invalid outfit selected
- {
- return false;
- }
+ // LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this));
+ // LLOutfitObserver::instance().addBOFReplacedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this));
- // *TODO This condition leads to menu item behavior inconsistent with
- // "Wear" button behavior and should be modified or removed.
- bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id;
+ // // Fetch "My Outfits" contents and refresh the list to display
+ // // initially fetched items. If not all items are fetched now
+ // // the observer will refresh the list as soon as the new items
+ // // arrive.
+ // category->fetch();
+ // refreshList(outfits);
+ // highlightBaseOutfit();
- if ("wear" == param)
- {
- return !is_worn;
- }
+ // mIsInitialized = true;
+ //}
- return true;
- }
+ LLAccordionCtrlTab* selected_tab = mAccordion->getSelectedTab();
+ if (!selected_tab) return;
- LLOutfitsList* mOutfitList;
- LLToggleableMenu* mMenu;
-};
+ // Pass focus to the selected outfit tab.
+ selected_tab->showAndFocusHeader();
+}
-//////////////////////////////////////////////////////////////////////////
-class LLOutfitContextMenu : public LLListContextMenu
+void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
{
-public:
-
- LLOutfitContextMenu(LLOutfitsList* outfit_list)
- : LLListContextMenu(),
- mOutfitList(outfit_list)
- {}
-protected:
- /* virtual */ LLContextMenu* createMenu()
- {
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
- LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
- LLUUID selected_id = mUUIDs.front();
-
- registrar.add("Outfit.WearReplace",
- boost::bind(&LLAppearanceMgr::replaceCurrentOutfit, &LLAppearanceMgr::instance(), selected_id));
- registrar.add("Outfit.WearAdd",
- boost::bind(&LLAppearanceMgr::addCategoryToCurrentOutfit, &LLAppearanceMgr::instance(), selected_id));
- registrar.add("Outfit.TakeOff",
- boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
- registrar.add("Outfit.Edit", boost::bind(editOutfit));
- registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
- registrar.add("Outfit.Delete", boost::bind(&LLOutfitsList::removeSelected, mOutfitList));
-
- enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2));
- enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitContextMenu::onVisible, this, _2));
-
- return createFromFile("menu_outfit_tab.xml");
- }
+ LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+ if (!cat) return;
- bool onEnable(LLSD::String param)
- {
- LLUUID outfit_cat_id = mUUIDs.back();
+ std::string name = cat->getName();
- if ("rename" == param)
- {
- return get_is_category_renameable(&gInventory, outfit_cat_id);
- }
- else if ("wear_replace" == param)
- {
- return LLAppearanceMgr::instance().getCanReplaceCOF(outfit_cat_id);
- }
- else if ("wear_add" == param)
- {
- return LLAppearanceMgr::getCanAddToCOF(outfit_cat_id);
- }
- else if ("take_off" == param)
- {
- return LLAppearanceMgr::getCanRemoveFromCOF(outfit_cat_id);
- }
+ outfit_accordion_tab_params tab_params(get_accordion_tab_params());
+ LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params);
+ if (!tab) return;
+ LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list);
+ wearable_list->setShape(tab->getLocalRect());
+ tab->addChild(wearable_list);
- return true;
- }
+ tab->setName(name);
+ tab->setTitle(name);
- bool onVisible(LLSD::String param)
- {
- LLUUID outfit_cat_id = mUUIDs.back();
- bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == outfit_cat_id;
+ // *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated.
+ tab->setDisplayChildren(false);
+ mAccordion->addCollapsibleCtrl(tab);
- if ("edit" == param)
- {
- return is_worn;
- }
- else if ("wear_replace" == param)
- {
- return !is_worn;
- }
- else if ("delete" == param)
- {
- return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id);
- }
+ // Start observing the new outfit category.
+ LLWearableItemsList* list = tab->getChild<LLWearableItemsList>("wearable_items_list");
+ if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id)))
+ {
+ // Remove accordion tab if category could not be added to observer.
+ mAccordion->removeCollapsibleCtrl(tab);
- return true;
- }
+ // kill removed tab
+ tab->die();
+ return;
+ }
- static void editOutfit()
- {
- LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit"));
- }
+ // Map the new tab with outfit category UUID.
+ mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));
- static void renameOutfit(const LLUUID& outfit_cat_id)
- {
- LLAppearanceMgr::instance().renameOutfit(outfit_cat_id);
- }
+ tab->setRightMouseDownCallback(boost::bind(&LLOutfitListBase::outfitRightClickCallBack, this,
+ _1, _2, _3, cat_id));
-private:
- LLOutfitsList* mOutfitList;
-};
+ // Setting tab focus callback to monitor currently selected outfit.
+ tab->setFocusReceivedCallback(boost::bind(&LLOutfitListBase::ñhangeOutfitSelection, this, list, cat_id));
-//////////////////////////////////////////////////////////////////////////
+ // Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875)
+ tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id));
-static LLPanelInjector<LLOutfitsList> t_outfits_list("outfits_list");
+ // force showing list items that don't match current filter(EXT-7158)
+ list->setForceShowingUnmatchedItems(true);
-LLOutfitsList::LLOutfitsList()
- : LLPanelAppearanceTab()
- , mAccordion(NULL)
- , mListCommands(NULL)
- , mIsInitialized(false)
- , mItemSelected(false)
-{
- mCategoriesObserver = new LLInventoryCategoriesObserver();
+ // Setting list commit callback to monitor currently selected wearable item.
+ list->setCommitCallback(boost::bind(&LLOutfitsList::onListSelectionChange, this, _1));
- mGearMenu = new LLOutfitListGearMenu(this);
- mOutfitMenu = new LLOutfitContextMenu(this);
-}
+ // Setting list refresh callback to apply filter on list change.
+ list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1));
-LLOutfitsList::~LLOutfitsList()
-{
- delete mGearMenu;
- delete mOutfitMenu;
+ list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3));
- if (gInventory.containsObserver(mCategoriesObserver))
- {
- gInventory.removeObserver(mCategoriesObserver);
- }
- delete mCategoriesObserver;
-}
+ // Fetch the new outfit contents.
+ cat->fetch();
-BOOL LLOutfitsList::postBuild()
-{
- mAccordion = getChild<LLAccordionCtrl>("outfits_accordion");
- mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR);
+ // Refresh the list of outfit items after fetch().
+ // Further list updates will be triggered by the category observer.
+ list->updateList(cat_id);
- LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
+ // If filter is currently applied we store the initial tab state and
+ // open it to show matched items if any.
+ if (!sFilterSubString.empty())
+ {
+ tab->notifyChildren(LLSD().with("action", "store_state"));
+ tab->setDisplayChildren(true);
- menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenu::updateItemsVisibility, mGearMenu));
- menu_gear_btn->setMenu(mGearMenu->getMenu());
+ // Setting mForceRefresh flag will make the list refresh its contents
+ // even if it is not currently visible. This is required to apply the
+ // filter to the newly added list.
+ list->setForceRefresh(true);
- return TRUE;
+ list->setFilterSubString(sFilterSubString);
+ }
}
-//virtual
-void LLOutfitsList::onOpen(const LLSD& /*info*/)
+void LLOutfitsList::updateRemovedCategory(LLUUID cat_id)
{
- if (!mIsInitialized)
- {
- // *TODO: I'm not sure is this check necessary but it never match while developing.
- if (!gInventory.isInventoryUsable())
- return;
-
- const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
-
- // *TODO: I'm not sure is this check necessary but it never match while developing.
- LLViewerInventoryCategory* category = gInventory.getCategory(outfits);
- if (!category)
- return;
-
- gInventory.addObserver(mCategoriesObserver);
-
- // Start observing changes in "My Outfits" category.
- mCategoriesObserver->addCategory(outfits,
- boost::bind(&LLOutfitsList::refreshList, this, outfits));
-
- const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
-
- // Start observing changes in Current Outfit category.
- mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this));
-
- LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this));
- LLOutfitObserver::instance().addBOFReplacedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this));
-
- // Fetch "My Outfits" contents and refresh the list to display
- // initially fetched items. If not all items are fetched now
- // the observer will refresh the list as soon as the new items
- // arrive.
- category->fetch();
- refreshList(outfits);
- highlightBaseOutfit();
-
- mIsInitialized = true;
- }
-
- LLAccordionCtrlTab* selected_tab = mAccordion->getSelectedTab();
- if (!selected_tab) return;
-
- // Pass focus to the selected outfit tab.
- selected_tab->showAndFocusHeader();
+ outfits_map_t::iterator outfits_iter = mOutfitsMap.find(cat_id);
+ if (outfits_iter != mOutfitsMap.end())
+ {
+ const LLUUID& outfit_id = outfits_iter->first;
+ LLAccordionCtrlTab* tab = outfits_iter->second;
+
+ // An outfit is removed from the list. Do the following:
+ // 1. Remove outfit category from observer to stop monitoring its changes.
+ mCategoriesObserver->removeCategory(outfit_id);
+
+ // 2. Remove the outfit from selection.
+ deselectOutfit(outfit_id);
+
+ // 3. Remove category UUID to accordion tab mapping.
+ mOutfitsMap.erase(outfits_iter);
+
+ // 4. Remove outfit tab from accordion.
+ mAccordion->removeCollapsibleCtrl(tab);
+
+ // kill removed tab
+ if (tab != NULL)
+ {
+ tab->die();
+ }
+ }
}
+/*
void LLOutfitsList::refreshList(const LLUUID& category_id)
{
LLInventoryModel::cat_array_t cat_array;
@@ -457,111 +322,114 @@ void LLOutfitsList::refreshList(const LLUUID& category_id)
++iter)
{
const LLUUID cat_id = (*iter);
- LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
- if (!cat) continue;
+ updateAddedCategory(cat_id);
+ //LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+ //if (!cat) continue;
- std::string name = cat->getName();
+ //std::string name = cat->getName();
- outfit_accordion_tab_params tab_params(get_accordion_tab_params());
- LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params);
- if (!tab) continue;
- LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list);
- wearable_list->setShape(tab->getLocalRect());
- tab->addChild(wearable_list);
+ //outfit_accordion_tab_params tab_params(get_accordion_tab_params());
+ //LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params);
+ //if (!tab) continue;
+ //LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list);
+ //wearable_list->setShape(tab->getLocalRect());
+ //tab->addChild(wearable_list);
- tab->setName(name);
- tab->setTitle(name);
+ //tab->setName(name);
+ //tab->setTitle(name);
- // *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated.
- tab->setDisplayChildren(false);
- mAccordion->addCollapsibleCtrl(tab);
+ //// *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated.
+ //tab->setDisplayChildren(false);
+ //mAccordion->addCollapsibleCtrl(tab);
- // Start observing the new outfit category.
- LLWearableItemsList* list = tab->getChild<LLWearableItemsList>("wearable_items_list");
- if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id)))
- {
- // Remove accordion tab if category could not be added to observer.
- mAccordion->removeCollapsibleCtrl(tab);
+ //// Start observing the new outfit category.
+ //LLWearableItemsList* list = tab->getChild<LLWearableItemsList>("wearable_items_list");
+ //if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id)))
+ //{
+ // // Remove accordion tab if category could not be added to observer.
+ // mAccordion->removeCollapsibleCtrl(tab);
- // kill removed tab
- tab->die();
- continue;
- }
+ // // kill removed tab
+ // tab->die();
+ // continue;
+ //}
- // Map the new tab with outfit category UUID.
- mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));
+ //// Map the new tab with outfit category UUID.
+ //mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));
- tab->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onAccordionTabRightClick, this,
- _1, _2, _3, cat_id));
+ //tab->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onAccordionTabRightClick, this,
+ // _1, _2, _3, cat_id));
- // Setting tab focus callback to monitor currently selected outfit.
- tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id));
+ //// Setting tab focus callback to monitor currently selected outfit.
+ //tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id));
- // Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875)
- tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id));
+ //// Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875)
+ //tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id));
- // force showing list items that don't match current filter(EXT-7158)
- list->setForceShowingUnmatchedItems(true);
+ //// force showing list items that don't match current filter(EXT-7158)
+ //list->setForceShowingUnmatchedItems(true);
- // Setting list commit callback to monitor currently selected wearable item.
- list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1));
+ //// Setting list commit callback to monitor currently selected wearable item.
+ //list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1));
- // Setting list refresh callback to apply filter on list change.
- list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1));
+ //// Setting list refresh callback to apply filter on list change.
+ //list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1));
- list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3));
+ //list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3));
- // Fetch the new outfit contents.
- cat->fetch();
+ //// Fetch the new outfit contents.
+ //cat->fetch();
- // Refresh the list of outfit items after fetch().
- // Further list updates will be triggered by the category observer.
- list->updateList(cat_id);
+ //// Refresh the list of outfit items after fetch().
+ //// Further list updates will be triggered by the category observer.
+ //list->updateList(cat_id);
- // If filter is currently applied we store the initial tab state and
- // open it to show matched items if any.
- if (!sFilterSubString.empty())
- {
- tab->notifyChildren(LLSD().with("action","store_state"));
- tab->setDisplayChildren(true);
+ //// If filter is currently applied we store the initial tab state and
+ //// open it to show matched items if any.
+ //if (!sFilterSubString.empty())
+ //{
+ // tab->notifyChildren(LLSD().with("action","store_state"));
+ // tab->setDisplayChildren(true);
- // Setting mForceRefresh flag will make the list refresh its contents
- // even if it is not currently visible. This is required to apply the
- // filter to the newly added list.
- list->setForceRefresh(true);
+ // // Setting mForceRefresh flag will make the list refresh its contents
+ // // even if it is not currently visible. This is required to apply the
+ // // filter to the newly added list.
+ // list->setForceRefresh(true);
- list->setFilterSubString(sFilterSubString);
- }
+ // list->setFilterSubString(sFilterSubString);
+ //}
}
// Handle removed tabs.
for (uuid_vec_t::const_iterator iter=vremoved.begin(); iter != vremoved.end(); ++iter)
{
- outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter));
- if (outfits_iter != mOutfitsMap.end())
- {
- const LLUUID& outfit_id = outfits_iter->first;
- LLAccordionCtrlTab* tab = outfits_iter->second;
-
- // An outfit is removed from the list. Do the following:
- // 1. Remove outfit category from observer to stop monitoring its changes.
- mCategoriesObserver->removeCategory(outfit_id);
-
- // 2. Remove the outfit from selection.
- deselectOutfit(outfit_id);
-
- // 3. Remove category UUID to accordion tab mapping.
- mOutfitsMap.erase(outfits_iter);
-
- // 4. Remove outfit tab from accordion.
- mAccordion->removeCollapsibleCtrl(tab);
-
- // kill removed tab
- if (tab != NULL)
- {
- tab->die();
- }
- }
+ const LLUUID cat_id = (*iter);
+ updateRemovedCategory(cat_id);
+ //outfits_map_t::iterator outfits_iter = mOutfitsMap.find(cat_id);
+ //if (outfits_iter != mOutfitsMap.end())
+ //{
+ // const LLUUID& outfit_id = outfits_iter->first;
+ // LLAccordionCtrlTab* tab = outfits_iter->second;
+
+ // // An outfit is removed from the list. Do the following:
+ // // 1. Remove outfit category from observer to stop monitoring its changes.
+ // mCategoriesObserver->removeCategory(outfit_id);
+
+ // // 2. Remove the outfit from selection.
+ // deselectOutfit(outfit_id);
+
+ // // 3. Remove category UUID to accordion tab mapping.
+ // mOutfitsMap.erase(outfits_iter);
+
+ // // 4. Remove outfit tab from accordion.
+ // mAccordion->removeCollapsibleCtrl(tab);
+
+ // // kill removed tab
+ // if (tab != NULL)
+ // {
+ // tab->die();
+ // }
+ //}
}
// Get changed items from inventory model and update outfit tabs
@@ -571,34 +439,29 @@ void LLOutfitsList::refreshList(const LLUUID& category_id)
items_iter != changed_items.end();
++items_iter)
{
- updateOutfitTab(*items_iter);
+ updateChangedCategoryName(*items_iter);
}
mAccordion->sort();
}
+*/
-void LLOutfitsList::highlightBaseOutfit()
+//virtual
+void LLOutfitsList::onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id)
{
- // id of base outfit
- LLUUID base_id = LLAppearanceMgr::getInstance()->getBaseOutfitUUID();
- if (base_id != mHighlightedOutfitUUID)
- {
- if (mOutfitsMap[mHighlightedOutfitUUID])
- {
- mOutfitsMap[mHighlightedOutfitUUID]->setTitleFontStyle("NORMAL");
- mOutfitsMap[mHighlightedOutfitUUID]->setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor"));
- }
-
- mHighlightedOutfitUUID = base_id;
- }
- if (mOutfitsMap[base_id])
+ if (mOutfitsMap[prev_id])
+ {
+ mOutfitsMap[prev_id]->setTitleFontStyle("NORMAL");
+ mOutfitsMap[prev_id]->setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor"));
+ }
+ if (mOutfitsMap[base_id])
{
mOutfitsMap[base_id]->setTitleFontStyle("BOLD");
mOutfitsMap[base_id]->setTitleColor(LLUIColorTable::instance().getColor("SelectedOutfitTextColor"));
}
}
-void LLOutfitsList::onSelectionChange(LLUICtrl* ctrl)
+void LLOutfitsList::onListSelectionChange(LLUICtrl* ctrl)
{
LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl);
if (!list) return;
@@ -606,10 +469,10 @@ void LLOutfitsList::onSelectionChange(LLUICtrl* ctrl)
LLViewerInventoryItem *item = gInventory.getItem(list->getSelectedUUID());
if (!item) return;
- changeOutfitSelection(list, item->getParentUUID());
+ ñhangeOutfitSelection(list, item->getParentUUID());
}
-void LLOutfitsList::performAction(std::string action)
+void LLOutfitListBase::performAction(std::string action)
{
if (mSelectedOutfitUUID.isNull()) return;
@@ -630,23 +493,7 @@ void LLOutfitsList::performAction(std::string action)
}
}
-void LLOutfitsList::removeSelected()
-{
- LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLOutfitsList::onOutfitsRemovalConfirmation, this, _1, _2));
-}
-
-void LLOutfitsList::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option != 0) return; // canceled
-
- if (mSelectedOutfitUUID.notNull())
- {
- gInventory.removeCategory(mSelectedOutfitUUID);
- }
-}
-
-void LLOutfitsList::setSelectedOutfitByUUID(const LLUUID& outfit_uuid)
+void LLOutfitsList::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid)
{
for (outfits_map_t::iterator iter = mOutfitsMap.begin();
iter != mOutfitsMap.end();
@@ -661,7 +508,7 @@ void LLOutfitsList::setSelectedOutfitByUUID(const LLUUID& outfit_uuid)
if (!list) continue;
tab->setFocus(TRUE);
- changeOutfitSelection(list, outfit_uuid);
+ ñhangeOutfitSelection(list, outfit_uuid);
tab->setDisplayChildren(true);
}
@@ -677,14 +524,14 @@ void LLOutfitsList::setFilterSubString(const std::string& string)
}
// virtual
-bool LLOutfitsList::isActionEnabled(const LLSD& userdata)
+bool LLOutfitListBase::isActionEnabled(const LLSD& userdata)
{
if (mSelectedOutfitUUID.isNull()) return false;
const std::string command_name = userdata.asString();
if (command_name == "delete")
{
- return !mItemSelected && LLAppearanceMgr::instance().getCanRemoveOutfit(mSelectedOutfitUUID);
+ return !hasItemSelected() && LLAppearanceMgr::instance().getCanRemoveOutfit(mSelectedOutfitUUID);
}
if (command_name == "rename")
{
@@ -745,7 +592,7 @@ void LLOutfitsList::getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const
}
}
-void LLOutfitsList::collapse_all_folders()
+void LLOutfitsList::onCollapseAllFolders()
{
for (outfits_map_t::iterator iter = mOutfitsMap.begin();
iter != mOutfitsMap.end();
@@ -759,7 +606,7 @@ void LLOutfitsList::collapse_all_folders()
}
}
-void LLOutfitsList::expand_all_folders()
+void LLOutfitsList::onExpandAllFolders()
{
for (outfits_map_t::iterator iter = mOutfitsMap.begin();
iter != mOutfitsMap.end();
@@ -773,11 +620,6 @@ void LLOutfitsList::expand_all_folders()
}
}
-boost::signals2::connection LLOutfitsList::setSelectionChangeCallback(selection_change_callback_t cb)
-{
- return mSelectionChangeSignal.connect(cb);
-}
-
bool LLOutfitsList::hasItemSelected()
{
return mItemSelected;
@@ -786,6 +628,7 @@ bool LLOutfitsList::hasItemSelected()
//////////////////////////////////////////////////////////////////////////
// Private methods
//////////////////////////////////////////////////////////////////////////
+/*
void LLOutfitsList::computeDifference(
const LLInventoryModel::cat_array_t& vcats,
uuid_vec_t& vadded,
@@ -811,17 +654,13 @@ void LLOutfitsList::computeDifference(
LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
}
+*/
-void LLOutfitsList::updateOutfitTab(const LLUUID& category_id)
+void LLOutfitsList::updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name)
{
- outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id);
+ outfits_map_t::iterator outfits_iter = mOutfitsMap.find(cat->getUUID());
if (outfits_iter != mOutfitsMap.end())
{
- LLViewerInventoryCategory *cat = gInventory.getCategory(category_id);
- if (!cat) return;
-
- std::string name = cat->getName();
-
// Update tab name with the new category name.
LLAccordionCtrlTab* tab = outfits_iter->second;
if (tab)
@@ -836,10 +675,10 @@ void LLOutfitsList::resetItemSelection(LLWearableItemsList* list, const LLUUID&
{
list->resetSelection();
mItemSelected = false;
- setSelectedOutfitUUID(category_id);
+ signalSelectionOutfitUUID(category_id);
}
-void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id)
+void LLOutfitsList::onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id)
{
MASK mask = gKeyboard->currentMask(TRUE);
@@ -865,12 +704,6 @@ void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUI
mItemSelected = list && (list->getSelectedItem() != NULL);
mSelectedListsMap.insert(wearables_lists_map_value_t(category_id, list));
- setSelectedOutfitUUID(category_id);
-}
-
-void LLOutfitsList::setSelectedOutfitUUID(const LLUUID& category_id)
-{
- mSelectionChangeSignal(mSelectedOutfitUUID = category_id);
}
void LLOutfitsList::deselectOutfit(const LLUUID& category_id)
@@ -881,7 +714,7 @@ void LLOutfitsList::deselectOutfit(const LLUUID& category_id)
// Reset selection if the outfit is selected.
if (category_id == mSelectedOutfitUUID)
{
- setSelectedOutfitUUID(LLUUID::null);
+ signalSelectionOutfitUUID(LLUUID::null);
}
}
@@ -890,7 +723,7 @@ void LLOutfitsList::restoreOutfitSelection(LLAccordionCtrlTab* tab, const LLUUID
// Try restoring outfit selection after filtering.
if (mAccordion->getSelectedTab() == tab)
{
- setSelectedOutfitUUID(category_id);
+ signalSelectionOutfitUUID(category_id);
}
}
@@ -1036,24 +869,6 @@ bool LLOutfitsList::canWearSelected()
return true;
}
-void LLOutfitsList::onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id)
-{
- LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl);
- if(mOutfitMenu && is_tab_header_clicked(tab, y) && cat_id.notNull())
- {
- // Focus tab header to trigger tab selection change.
- LLUICtrl* header = tab->findChild<LLUICtrl>("dd_header");
- if (header)
- {
- header->setFocus(TRUE);
- }
-
- uuid_vec_t selected_uuids;
- selected_uuids.push_back(cat_id);
- mOutfitMenu->show(ctrl, selected_uuids, x, y);
- }
-}
-
void LLOutfitsList::wearSelectedItems()
{
uuid_vec_t selected_uuids;
@@ -1132,6 +947,47 @@ void LLOutfitsList::onCOFChanged()
}
}
+void LLOutfitsList::getCurrentCategories(uuid_vec_t& vcur)
+{
+ // Creating a vector of currently displayed sub-categories UUIDs.
+ for (outfits_map_t::const_iterator iter = mOutfitsMap.begin();
+ iter != mOutfitsMap.end();
+ iter++)
+ {
+ vcur.push_back((*iter).first);
+ }
+}
+
+
+void LLOutfitsList::sortOutfits()
+{
+ mAccordion->sort();
+}
+
+void LLOutfitsList::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id)
+{
+ LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl);
+ if (mOutfitMenu && is_tab_header_clicked(tab, y) && cat_id.notNull())
+ {
+ // Focus tab header to trigger tab selection change.
+ LLUICtrl* header = tab->findChild<LLUICtrl>("dd_header");
+ if (header)
+ {
+ header->setFocus(TRUE);
+ }
+
+ uuid_vec_t selected_uuids;
+ selected_uuids.push_back(cat_id);
+ mOutfitMenu->show(ctrl, selected_uuids, x, y);
+ }
+}
+
+LLOutfitListGearMenuBase* LLOutfitsList::createGearMenu()
+{
+ return new LLOutfitListGearMenu(this);
+}
+
+
bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y)
{
if(!tab || !tab->getHeaderVisible()) return false;
@@ -1140,4 +996,490 @@ bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y)
return y >= header_bottom;
}
+LLOutfitListBase::LLOutfitListBase()
+ : LLPanelAppearanceTab()
+ , mIsInitialized(false)
+{
+ mCategoriesObserver = new LLInventoryCategoriesObserver();
+ mOutfitMenu = new LLOutfitContextMenu(this);
+ //mGearMenu = createGearMenu();
+}
+
+LLOutfitListBase::~LLOutfitListBase()
+{
+ delete mOutfitMenu;
+ delete mGearMenu;
+
+ if (gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ }
+ delete mCategoriesObserver;
+}
+
+void LLOutfitListBase::onOpen(const LLSD& info)
+{
+ if (!mIsInitialized)
+ {
+ // *TODO: I'm not sure is this check necessary but it never match while developing.
+ if (!gInventory.isInventoryUsable())
+ return;
+
+ const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ // *TODO: I'm not sure is this check necessary but it never match while developing.
+ LLViewerInventoryCategory* category = gInventory.getCategory(outfits);
+ if (!category)
+ return;
+
+ gInventory.addObserver(mCategoriesObserver);
+
+ // Start observing changes in "My Outfits" category.
+ mCategoriesObserver->addCategory(outfits,
+ boost::bind(&LLOutfitListBase::refreshList, this, outfits));
+
+ const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+
+ // Start observing changes in Current Outfit category.
+ //mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this));
+
+ LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(&LLOutfitListBase::highlightBaseOutfit, this));
+ LLOutfitObserver::instance().addBOFReplacedCallback(boost::bind(&LLOutfitListBase::highlightBaseOutfit, this));
+
+ // Fetch "My Outfits" contents and refresh the list to display
+ // initially fetched items. If not all items are fetched now
+ // the observer will refresh the list as soon as the new items
+ // arrive.
+ category->fetch();
+ refreshList(outfits);
+ highlightBaseOutfit();
+
+ mIsInitialized = true;
+ }
+
+ //LLAccordionCtrlTab* selected_tab = mAccordion->getSelectedTab();
+ //if (!selected_tab) return;
+
+ //// Pass focus to the selected outfit tab.
+ //selected_tab->showAndFocusHeader();
+}
+
+void LLOutfitListBase::refreshList(const LLUUID& category_id)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ // Collect all sub-categories of a given category.
+ LLIsType is_category(LLAssetType::AT_CATEGORY);
+ gInventory.collectDescendentsIf(
+ category_id,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_category);
+
+ uuid_vec_t vadded;
+ uuid_vec_t vremoved;
+
+ // Create added and removed items vectors.
+ computeDifference(cat_array, vadded, vremoved);
+
+ // Handle added tabs.
+ for (uuid_vec_t::const_iterator iter = vadded.begin();
+ iter != vadded.end();
+ ++iter)
+ {
+ const LLUUID cat_id = (*iter);
+ updateAddedCategory(cat_id);
+ }
+
+ // Handle removed tabs.
+ for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter)
+ {
+ const LLUUID cat_id = (*iter);
+ updateRemovedCategory(cat_id);
+ }
+
+ // Get changed items from inventory model and update outfit tabs
+ // which might have been renamed.
+ const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
+ for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
+ items_iter != changed_items.end();
+ ++items_iter)
+ {
+ LLViewerInventoryCategory *cat = gInventory.getCategory(*items_iter);
+ if (!cat) return;
+
+ std::string name = cat->getName();
+
+ updateChangedCategoryName(cat, name);
+ }
+
+ sortOutfits();
+}
+
+void LLOutfitListBase::computeDifference(
+ const LLInventoryModel::cat_array_t& vcats,
+ uuid_vec_t& vadded,
+ uuid_vec_t& vremoved)
+{
+ uuid_vec_t vnew;
+ // Creating a vector of newly collected sub-categories UUIDs.
+ for (LLInventoryModel::cat_array_t::const_iterator iter = vcats.begin();
+ iter != vcats.end();
+ iter++)
+ {
+ vnew.push_back((*iter)->getUUID());
+ }
+
+ uuid_vec_t vcur;
+ //// Creating a vector of currently displayed sub-categories UUIDs.
+ //for (outfits_map_t::const_iterator iter = mOutfitsMap.begin();
+ // iter != mOutfitsMap.end();
+ // iter++)
+ //{
+ // vcur.push_back((*iter).first);
+ //}
+ getCurrentCategories(vcur);
+
+ LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
+}
+
+void LLOutfitListBase::sortOutfits()
+{
+}
+
+void LLOutfitListBase::highlightBaseOutfit()
+{
+ // id of base outfit
+ LLUUID base_id = LLAppearanceMgr::getInstance()->getBaseOutfitUUID();
+ if (base_id != mHighlightedOutfitUUID)
+ {
+ LLUUID prev_id = mHighlightedOutfitUUID;
+ mHighlightedOutfitUUID = base_id;
+ onHighlightBaseOutfit(base_id, prev_id);
+ }
+
+}
+
+void LLOutfitListBase::removeSelected()
+{
+ LLNotificationsUtil::add("DeleteOutfits", LLSD(), LLSD(), boost::bind(&LLOutfitListBase::onOutfitsRemovalConfirmation, this, _1, _2));
+}
+
+void LLOutfitListBase::onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return; // canceled
+
+ if (mSelectedOutfitUUID.notNull())
+ {
+ gInventory.removeCategory(mSelectedOutfitUUID);
+ }
+}
+
+void LLOutfitListBase::setSelectedOutfitByUUID(const LLUUID& outfit_uuid)
+{
+ onSetSelectedOutfitByUUID(outfit_uuid);
+}
+
+boost::signals2::connection LLOutfitListBase::setSelectionChangeCallback(selection_change_callback_t cb)
+{
+ return mSelectionChangeSignal.connect(cb);
+}
+
+void LLOutfitListBase::signalSelectionOutfitUUID(const LLUUID& category_id)
+{
+ mSelectionChangeSignal(category_id);
+}
+
+void LLOutfitListBase::outfitRightClickCallBack(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id)
+{
+ onOutfitRightClick(ctrl, x, y, cat_id);
+}
+
+void LLOutfitListBase::ñhangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id)
+{
+ onChangeOutfitSelection(list, category_id);
+ mSelectedOutfitUUID = category_id;
+ signalSelectionOutfitUUID(category_id);
+}
+
+BOOL LLOutfitListBase::postBuild()
+{
+ mGearMenu = createGearMenu();
+
+ LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
+
+ menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenuBase::updateItemsVisibility, mGearMenu));
+ menu_gear_btn->setMenu(mGearMenu->getMenu());
+ return TRUE;
+}
+
+void LLOutfitListBase::collapseAllFolders()
+{
+ onCollapseAllFolders();
+}
+
+void LLOutfitListBase::expandAllFolders()
+{
+ onExpandAllFolders();
+}
+
+LLContextMenu* LLOutfitContextMenu::createMenu()
+{
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ LLUUID selected_id = mUUIDs.front();
+
+ registrar.add("Outfit.WearReplace",
+ boost::bind(&LLAppearanceMgr::replaceCurrentOutfit, &LLAppearanceMgr::instance(), selected_id));
+ registrar.add("Outfit.WearAdd",
+ boost::bind(&LLAppearanceMgr::addCategoryToCurrentOutfit, &LLAppearanceMgr::instance(), selected_id));
+ registrar.add("Outfit.TakeOff",
+ boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
+ registrar.add("Outfit.Edit", boost::bind(editOutfit));
+ registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
+ registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList));
+
+ enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2));
+ enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitContextMenu::onVisible, this, _2));
+
+ return createFromFile("menu_outfit_tab.xml");
+
+}
+
+bool LLOutfitContextMenu::onEnable(LLSD::String param)
+{
+ LLUUID outfit_cat_id = mUUIDs.back();
+
+ if ("rename" == param)
+ {
+ return get_is_category_renameable(&gInventory, outfit_cat_id);
+ }
+ else if ("wear_replace" == param)
+ {
+ return LLAppearanceMgr::instance().getCanReplaceCOF(outfit_cat_id);
+ }
+ else if ("wear_add" == param)
+ {
+ return LLAppearanceMgr::getCanAddToCOF(outfit_cat_id);
+ }
+ else if ("take_off" == param)
+ {
+ return LLAppearanceMgr::getCanRemoveFromCOF(outfit_cat_id);
+ }
+
+ return true;
+}
+
+bool LLOutfitContextMenu::onVisible(LLSD::String param)
+{
+ LLUUID outfit_cat_id = mUUIDs.back();
+ bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == outfit_cat_id;
+
+ if ("edit" == param)
+ {
+ return is_worn;
+ }
+ else if ("wear_replace" == param)
+ {
+ return !is_worn;
+ }
+ else if ("delete" == param)
+ {
+ return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id);
+ }
+
+ return true;
+}
+
+//static
+void LLOutfitContextMenu::editOutfit()
+{
+ LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit"));
+}
+
+void LLOutfitContextMenu::renameOutfit(const LLUUID& outfit_cat_id)
+{
+ LLAppearanceMgr::instance().renameOutfit(outfit_cat_id);
+}
+
+LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)
+ : mOutfitList(olist),
+ mMenu(NULL)
+{
+ llassert_always(mOutfitList);
+
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+ registrar.add("Gear.Wear", boost::bind(&LLOutfitListGearMenuBase::onWear, this));
+ registrar.add("Gear.TakeOff", boost::bind(&LLOutfitListGearMenuBase::onTakeOff, this));
+ registrar.add("Gear.Rename", boost::bind(&LLOutfitListGearMenuBase::onRename, this));
+ registrar.add("Gear.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList));
+ registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenuBase::onCreate, this, _2));
+ registrar.add("Gear.Collapse", boost::bind(&LLOutfitListBase::onCollapseAllFolders, mOutfitList));
+ registrar.add("Gear.Expand", boost::bind(&LLOutfitListBase::onExpandAllFolders, mOutfitList));
+
+ registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this));
+
+ registrar.add("Gear.UploadFoto", boost::bind(&LLOutfitListGearMenuBase::onUploadFoto, this));
+ registrar.add("Gear.LoadAssets", boost::bind(&LLOutfitListGearMenuBase::onLoadAssets, this));
+
+ enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenuBase::onEnable, this, _2));
+ enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenuBase::onVisible, this, _2));
+
+ mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
+ "menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ llassert(mMenu);
+}
+
+void LLOutfitListGearMenuBase::updateItemsVisibility()
+{
+ onUpdateItemsVisibility();
+}
+
+void LLOutfitListGearMenuBase::onUpdateItemsVisibility()
+{
+ if (!mMenu) return;
+
+ bool have_selection = getSelectedOutfitID().notNull();
+ mMenu->setItemVisible("sepatator1", have_selection);
+ mMenu->setItemVisible("sepatator2", have_selection);
+ //mMenu->setItemVisible("expand", mOutfitList->getHasExpandableFolders());
+ //mMenu->setItemVisible("collapse", mOutfitList->getHasExpandableFolders());
+ mMenu->arrangeAndClear(); // update menu height
+}
+
+LLToggleableMenu* LLOutfitListGearMenuBase::getMenu()
+{
+ return mMenu;
+}
+const LLUUID& LLOutfitListGearMenuBase::getSelectedOutfitID()
+{
+ return mOutfitList->getSelectedOutfitUUID();
+}
+
+LLViewerInventoryCategory* LLOutfitListGearMenuBase::getSelectedOutfit()
+{
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.isNull())
+ {
+ return NULL;
+ }
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id);
+ return cat;
+}
+
+void LLOutfitListGearMenuBase::onWear()
+{
+ LLViewerInventoryCategory* selected_outfit = getSelectedOutfit();
+ if (selected_outfit)
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory(
+ selected_outfit, /*copy=*/ FALSE, /*append=*/ FALSE);
+ }
+}
+
+void LLOutfitListGearMenuBase::onAdd()
+{
+ const LLUUID& selected_id = getSelectedOutfitID();
+
+ if (selected_id.notNull())
+ {
+ LLAppearanceMgr::getInstance()->addCategoryToCurrentOutfit(selected_id);
+ }
+}
+
+void LLOutfitListGearMenuBase::onTakeOff()
+{
+ // Take off selected outfit.
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.notNull())
+ {
+ LLAppearanceMgr::instance().takeOffOutfit(selected_outfit_id);
+ }
+}
+
+void LLOutfitListGearMenuBase::onRename()
+{
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.notNull())
+ {
+ LLAppearanceMgr::instance().renameOutfit(selected_outfit_id);
+ }
+}
+
+void LLOutfitListGearMenuBase::onCreate(const LLSD& data)
+{
+ LLWearableType::EType type = LLWearableType::typeNameToType(data.asString());
+ if (type == LLWearableType::WT_NONE)
+ {
+ LL_WARNS() << "Invalid wearable type" << LL_ENDL;
+ return;
+ }
+
+ LLAgentWearables::createWearable(type, true);
+}
+
+bool LLOutfitListGearMenuBase::onEnable(LLSD::String param)
+{
+ // Handle the "Wear - Replace Current Outfit" menu option specially
+ // because LLOutfitList::isActionEnabled() checks whether it's allowed
+ // to wear selected outfit OR selected items, while we're only
+ // interested in the outfit (STORM-183).
+ if ("wear" == param)
+ {
+ return LLAppearanceMgr::instance().getCanReplaceCOF(mOutfitList->getSelectedOutfitUUID());
+ }
+
+ return mOutfitList->isActionEnabled(param);
+}
+
+bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
+{
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ if (selected_outfit_id.isNull()) // no selection or invalid outfit selected
+ {
+ return false;
+ }
+
+ // *TODO This condition leads to menu item behavior inconsistent with
+ // "Wear" button behavior and should be modified or removed.
+ bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id;
+
+ if ("wear" == param)
+ {
+ return !is_worn;
+ }
+
+ return true;
+}
+
+void LLOutfitListGearMenuBase::onUploadFoto()
+{
+
+}
+
+void LLOutfitListGearMenuBase::onLoadAssets()
+{
+
+}
+
+LLOutfitListGearMenu::LLOutfitListGearMenu(LLOutfitListBase* olist)
+ : LLOutfitListGearMenuBase(olist)
+{}
+
+void LLOutfitListGearMenu::onUpdateItemsVisibility()
+{
+ if (!mMenu) return;
+ mMenu->setItemVisible("expand", TRUE);
+ mMenu->setItemVisible("collapse", TRUE);
+ mMenu->setItemVisible("upload_foto", FALSE);
+ mMenu->setItemVisible("load_assets", TRUE);
+ LLOutfitListGearMenuBase::onUpdateItemsVisibility();
+}
+
// EOF
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index 2e3fb3f488..f4b02991e5 100755
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -32,11 +32,14 @@
// newview
#include "llinventorymodel.h"
+#include "lllistcontextmenu.h"
#include "llpanelappearancetab.h"
+#include "lltoggleablemenu.h"
+#include "llviewermenu.h"
class LLAccordionCtrlTab;
class LLInventoryCategoriesObserver;
-class LLOutfitListGearMenu;
+class LLOutfitListGearMenuBase;
class LLWearableItemsList;
class LLListContextMenu;
@@ -57,6 +60,134 @@ public:
/*virtual*/ bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const;
};
+class LLOutfitListBase : public LLPanelAppearanceTab
+{
+public:
+ typedef boost::function<void(const LLUUID&)> selection_change_callback_t;
+ typedef boost::signals2::signal<void(const LLUUID&)> selection_change_signal_t;
+
+ LLOutfitListBase();
+ virtual ~LLOutfitListBase();
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void onOpen(const LLSD& info);
+
+ void refreshList(const LLUUID& category_id);
+ void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved);
+ // highlights currently worn outfit in list and unhighlights previously worn
+ void highlightBaseOutfit();
+ void ñhangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
+
+
+ virtual void getCurrentCategories(uuid_vec_t& vcur) = 0;
+ virtual void updateAddedCategory(LLUUID cat_id) = 0;
+ virtual void updateRemovedCategory(LLUUID cat_id) = 0;
+ virtual void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name) = 0;
+ virtual void sortOutfits();
+
+ void removeSelected();
+ void setSelectedOutfitByUUID(const LLUUID& outfit_uuid);
+ const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; }
+ boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
+ void outfitRightClickCallBack(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
+
+ virtual bool isActionEnabled(const LLSD& userdata);
+ virtual void performAction(std::string action);
+ virtual bool hasItemSelected() = 0;
+ virtual bool canWearSelected() = 0;
+
+ void signalSelectionOutfitUUID(const LLUUID& category_id);
+
+ void collapseAllFolders();
+ virtual void onCollapseAllFolders() = 0;
+
+ void expandAllFolders();
+ virtual void onExpandAllFolders() = 0;
+
+ virtual bool getHasExpandableFolders() = 0;
+
+protected:
+ virtual LLOutfitListGearMenuBase* createGearMenu() = 0;
+ virtual void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id) = 0;
+ virtual void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) = 0;
+ virtual void onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) = 0;
+ void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response);
+ virtual void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) = 0;
+
+ bool mIsInitialized;
+ LLInventoryCategoriesObserver* mCategoriesObserver;
+ LLUUID mSelectedOutfitUUID;
+ // id of currently highlited outfit
+ LLUUID mHighlightedOutfitUUID;
+ selection_change_signal_t mSelectionChangeSignal;
+ LLListContextMenu* mOutfitMenu;
+ LLOutfitListGearMenuBase* mGearMenu;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+class LLOutfitContextMenu : public LLListContextMenu
+{
+public:
+
+ LLOutfitContextMenu(LLOutfitListBase* outfit_list)
+ : LLListContextMenu(),
+ mOutfitList(outfit_list)
+ {}
+protected:
+ /* virtual */ LLContextMenu* createMenu();
+
+ bool onEnable(LLSD::String param);
+
+ bool onVisible(LLSD::String param);
+
+ static void editOutfit();
+
+ static void renameOutfit(const LLUUID& outfit_cat_id);
+
+private:
+ LLOutfitListBase* mOutfitList;
+};
+
+class LLOutfitListGearMenuBase
+{
+public:
+ LLOutfitListGearMenuBase(LLOutfitListBase* olist);
+
+ void updateItemsVisibility();
+
+ LLToggleableMenu* getMenu();
+
+protected:
+ virtual void onUpdateItemsVisibility();
+ virtual void onUploadFoto();
+ virtual void onLoadAssets();
+ const LLUUID& getSelectedOutfitID();
+
+ LLOutfitListBase* mOutfitList;
+ LLToggleableMenu* mMenu;
+private:
+
+ LLViewerInventoryCategory* getSelectedOutfit();
+
+ void onWear();
+ void onAdd();
+ void onTakeOff();
+ void onRename();
+ void onCreate(const LLSD& data);
+ bool onEnable(LLSD::String param);
+ bool onVisible(LLSD::String param);
+};
+
+class LLOutfitListGearMenu : public LLOutfitListGearMenuBase
+{
+public:
+ LLOutfitListGearMenu(LLOutfitListBase* olist);
+
+protected:
+ /*virtual*/ void onUpdateItemsVisibility();
+};
+
/**
* @class LLOutfitsList
*
@@ -66,11 +197,9 @@ public:
*
* Starts fetching necessary inventory content on first opening.
*/
-class LLOutfitsList : public LLPanelAppearanceTab
+class LLOutfitsList : public LLOutfitListBase
{
public:
- typedef boost::function<void (const LLUUID&)> selection_change_callback_t;
- typedef boost::signals2::signal<void (const LLUUID&)> selection_change_signal_t;
LLOutfitsList();
virtual ~LLOutfitsList();
@@ -79,63 +208,66 @@ public:
/*virtual*/ void onOpen(const LLSD& info);
- void refreshList(const LLUUID& category_id);
-
- // highlits currently worn outfit tab text and unhighlights previously worn
- void highlightBaseOutfit();
- void performAction(std::string action);
+ //virtual void refreshList(const LLUUID& category_id);
- void removeSelected();
+ /*virtual*/ void updateAddedCategory(LLUUID cat_id);
+ /*virtual*/ void updateRemovedCategory(LLUUID cat_id);
- void setSelectedOutfitByUUID(const LLUUID& outfit_uuid);
+ // highlits currently worn outfit tab text and unhighlights previously worn
+ /*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id);
- /*virtual*/ void setFilterSubString(const std::string& string);
+ //void performAction(std::string action);
- /*virtual*/ bool isActionEnabled(const LLSD& userdata);
- const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; }
+ /*virtual*/ void setFilterSubString(const std::string& string);
/*virtual*/ void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const;
- boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
-
- // Collects selected items from all selected lists and wears them(if possible- adds, else replaces)
+ // Collects selected items from all selected lists and wears them(if possible- adds, else replaces)
void wearSelectedItems();
/**
* Returns true if there is a selection inside currently selected outfit
*/
- bool hasItemSelected();
+ /*virtual*/ bool hasItemSelected();
/**
Collapses all outfit accordions.
*/
- void collapse_all_folders();
+ /*virtual*/ void onCollapseAllFolders();
/**
Expands all outfit accordions.
*/
- void expand_all_folders();
+ void onExpandAllFolders();
+ /*virtual*/ bool getHasExpandableFolders() { return TRUE; }
-private:
+protected:
+ LLOutfitListGearMenuBase* createGearMenu();
- void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response);
+private:
/**
* Wrapper for LLCommonUtils::computeDifference. @see LLCommonUtils::computeDifference
*/
- void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved);
+ //void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved);
+
+ void getCurrentCategories(uuid_vec_t& vcur);
/**
* Updates tab displaying outfit identified by category_id.
*/
- void updateOutfitTab(const LLUUID& category_id);
+ /*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name);
+
+ /*virtual*/ void sortOutfits();
+
+ /*virtual*/ void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid);
/**
* Resets previous selection and stores newly selected list and outfit id.
*/
- void changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
+ /*virtual*/ void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
/**
*Resets items selection inside outfit
@@ -143,11 +275,6 @@ private:
void resetItemSelection(LLWearableItemsList* list, const LLUUID& category_id);
/**
- * Saves newly selected outfit ID.
- */
- void setSelectedOutfitUUID(const LLUUID& category_id);
-
- /**
* Removes the outfit from selection.
*/
void deselectOutfit(const LLUUID& category_id);
@@ -182,15 +309,16 @@ private:
*/
bool canWearSelected();
- void onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
void onCOFChanged();
- void onSelectionChange(LLUICtrl* ctrl);
+ void onListSelectionChange(LLUICtrl* ctrl);
+
+ /*virtual*/ void onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
static void onOutfitRename(const LLSD& notification, const LLSD& response);
- LLInventoryCategoriesObserver* mCategoriesObserver;
+ //LLInventoryCategoriesObserver* mCategoriesObserver;
LLAccordionCtrl* mAccordion;
LLPanel* mListCommands;
@@ -199,11 +327,6 @@ private:
typedef wearables_lists_map_t::value_type wearables_lists_map_value_t;
wearables_lists_map_t mSelectedListsMap;
- LLUUID mSelectedOutfitUUID;
- // id of currently highlited outfit
- LLUUID mHighlightedOutfitUUID;
- selection_change_signal_t mSelectionChangeSignal;
-
typedef std::map<LLUUID, LLAccordionCtrlTab*> outfits_map_t;
typedef outfits_map_t::value_type outfits_map_value_t;
outfits_map_t mOutfitsMap;
@@ -212,10 +335,9 @@ private:
// Used to monitor COF changes for updating items worn state. See EXT-8636.
uuid_vec_t mCOFLinkedItems;
- LLOutfitListGearMenu* mGearMenu;
- LLListContextMenu* mOutfitMenu;
+ //LLOutfitListGearMenu* mGearMenu;
- bool mIsInitialized;
+ //bool mIsInitialized;
/**
* True if there is a selection inside currently selected outfit
*/
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index 1e1f59055f..eb88abb2bf 100755
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -37,6 +37,7 @@
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "lloutfitobserver.h"
+#include "lloutfitgallery.h"
#include "lloutfitslist.h"
#include "llpanelwearing.h"
#include "llsaveoutfitcombobtn.h"
@@ -44,6 +45,7 @@
#include "llviewerfoldertype.h"
static const std::string OUTFITS_TAB_NAME = "outfitslist_tab";
+static const std::string OUTFIT_GALLERY_TAB_NAME = "outfit_gallery_tab";
static const std::string COF_TAB_NAME = "cof_tab";
static LLPanelInjector<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory");
@@ -268,12 +270,16 @@ bool LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
void LLPanelOutfitsInventory::initTabPanels()
{
+ //TODO: Add LLOutfitGallery change callback
mCurrentOutfitPanel = findChild<LLPanelWearing>(COF_TAB_NAME);
mCurrentOutfitPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this));
mMyOutfitsPanel = findChild<LLOutfitsList>(OUTFITS_TAB_NAME);
mMyOutfitsPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this));
+ mOutfitGalleryPanel = findChild<LLOutfitGallery>(OUTFIT_GALLERY_TAB_NAME);
+ mOutfitGalleryPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this));
+
mAppearanceTabs = getChild<LLTabContainer>("appearance_tabs");
mAppearanceTabs->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::onTabChange, this));
}
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index a7917b457c..8c873df038 100755
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -30,8 +30,9 @@
#include "llpanel.h"
+class LLOutfitGallery;
class LLOutfitsList;
-class LLOutfitListGearMenu;
+class LLOutfitListGearMenuBase;
class LLPanelAppearanceTab;
class LLPanelWearing;
class LLMenuGL;
@@ -76,6 +77,7 @@ protected:
private:
LLPanelAppearanceTab* mActivePanel;
LLOutfitsList* mMyOutfitsPanel;
+ LLOutfitGallery* mOutfitGalleryPanel;
LLPanelWearing* mCurrentOutfitPanel;
// tab panels //
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 980810835e..1e9d0f912f 100755
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -71,6 +71,7 @@
#include "llradiogroup.h"
#include "llfloaterreg.h"
#include "lllocalbitmaps.h"
+#include "llerror.h"
static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
@@ -573,6 +574,7 @@ void LLFloaterTexturePicker::draw()
mTexturep = NULL;
if(mImageAssetID.notNull())
{
+ LL_WARNS() << "mImageAssetID: " << mImageAssetID << LL_ENDL;
mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID);
mTexturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
}
diff --git a/indra/newview/skins/default/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
<texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/>
<texture name="NavBar Separator" file_name="navbar/separator.png"/>
+ <texture name="Outfit_Default_Foto" fileName="icons/pop_up_caution.png"/>
</textures>
diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml
index 76adaad57c..420aced6a2 100755
--- a/indra/newview/skins/default/xui/en/floater_snapshot.xml
+++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml
@@ -406,7 +406,7 @@
width="400"
height="400"
follows="top|left"/>
- <view_border
+ <!--view_border
bevel_style="in"
height="21"
layout="topleft"
@@ -414,7 +414,7 @@
top_pad="0"
right="-10"
follows="left|top|right"
- left_delta="0"/>
+ left_delta="0"/>-->
<text
type="string"
font="SansSerifSmall"
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
index 3b8ace6308..c970efbc03 100755
--- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
@@ -39,8 +39,22 @@
function="Gear.OnVisible"
parameter="take_off" />
</menu_item_call>
+ <menu_item_call
+ label="Upload foto"
+ layout="topleft"
+ name="upload_foto">
+ <on_click
+ function="Gear.UploadFoto" />
+ </menu_item_call>
+ <menu_item_call
+ label="Load assets"
+ layout="topleft"
+ name="load_assets">
+ <on_click
+ function="Gear.LoadAssets" />
+ </menu_item_call>
- <menu_item_separator name="sepatator1" />
+ <menu_item_separator name="sepatator1" />
<!-- copied (with minor modifications) from menu_inventory_add.xml -->
<!-- *TODO: generate dynamically? -->
<menu
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
new file mode 100644
index 0000000000..6146514f98
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ border="false"
+ follows="all"
+ height="430"
+ name="Outfit Gallery"
+ layout="topleft"
+ left="0"
+ top="0"
+ width="312">
+ <string name="outfit_foto_string">
+ Foto of "[OUTFIT_NAME]" outfit
+ </string>
+ <scroll_container
+ border="true"
+ bevel_style="none"
+ follows="all"
+ height="400"
+ width="312"
+ min_width="312"
+ layout="topleft"
+ left="4"
+ top="0"
+ name="gallery_scroll_panel"
+ opaque="false"
+ top_pad="0">
+ <panel
+ background_visible="true"
+ border="true"
+ bevel_style="none"
+ follows="all"
+ height="560"
+ width="312"
+ layout="topleft"
+ top="0"
+ left="4"
+ top_pad="0"
+ visible="true"
+ name="gallery_panel">
+ <!--outfit_gallery_item
+ layout="topleft"
+ left="10"
+ name="preview_outfit1"
+ height="175"
+ width="150"
+ follows="left|top"/-->
+ <!--layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="0" name="top_gallery_stack" orientation="horizontal">
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ </layout_stack>
+ <layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="190" name="top_gallery_stack" orientation="horizontal">
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ </layout_stack>
+ <layout_stack follows="left|right" height="180" width="498" layout="topleft" left="0" animate="false" top="380" name="top_gallery_stack" orientation="horizontal">
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top_gallery_panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit1" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ <layout_panel follows="left|top" height="175" width="166" layout="topleft" left="0" top="0" auto_resize="false" visible="true" name="top panel">
+ <outfit_gallery_item layout="topleft" left="10" name="preview_outfit2" height="175" width="150" follows="left|top"/>
+ </layout_panel>
+ </layout_stack-->
+ </panel>
+ </scroll_container>
+ <panel
+ background_visible="true"
+ follows="bottom|left|right"
+ height="28"
+ layout="topleft"
+ left="4"
+ top_pad="0"
+ visible="true"
+ name="bottom_panel"
+ width="312">
+ <menu_button
+ follows="bottom|left"
+ tool_tip="Show additional options"
+ height="25"
+ image_hover_unselected="Toolbar_Left_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Left_Selected"
+ image_unselected="Toolbar_Left_Off"
+ layout="topleft"
+ left="0"
+ name="options_gear_btn"
+ top="1"
+ width="31" />
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="dummy_icon"
+ width="243"/>
+ <button
+ follows="bottom|right"
+ height="25"
+ image_hover_unselected="Toolbar_Right_Over"
+ image_overlay="TrashItem_Off"
+ image_selected="Toolbar_Right_Selected"
+ image_unselected="Toolbar_Right_Off"
+ layout="topleft"
+ left_pad="1"
+ name="trash_btn"
+ tool_tip="Delete selected outfit"
+ width="31"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml b/indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml
new file mode 100644
index 0000000000..acb72402cc
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_outfit_gallery_item.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ border="true"
+ bevel_style="none"
+ follows="left|top"
+ height="169"
+ width="149"
+ name="Outfit Gallery Item"
+ layout="topleft"
+ left="0"
+ top="0"
+ >
+ <icon
+ left="0"
+ top="0"
+ layout="topleft"
+ name="preview_outfit"
+ height="149"
+ width="149"
+ follows="left|top"
+ visible="true"
+ image_name="Popup_Caution"
+ />
+ <text
+ length="1"
+ follows="left|top"
+ left="1"
+ height="10"
+ layout="topleft"
+ name="outfit_name"
+ top="150"
+ width="150">
+ Summer hipster, Pierce
+ </text>
+ <text
+ length="1"
+ follows="left|top"
+ left="1"
+ height="10"
+ layout="topleft"
+ name="outfit_worn_text"
+ top="160"
+ width="150">
+ (worn)
+ </text>
+
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
index 405d9513db..ff0714adbb 100755
--- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
@@ -33,6 +33,17 @@
top="8"
width="315">
<panel
+ class="outfit_gallery"
+ filename="panel_outfit_gallery.xml"
+ height="520"
+ name="outfit_gallery_tab"
+ background_visible="true"
+ help_topic="outfit_gallery_tab"
+ follows="all"
+ label="OUTFIT GALLERY"
+ layout="topleft"
+ width="315" />
+ <panel
class="outfits_list"
filename="panel_outfits_list.xml"
height="520"