diff options
Diffstat (limited to 'indra/newview/llpanelwearing.cpp')
-rw-r--r-- | indra/newview/llpanelwearing.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp new file mode 100644 index 0000000000..fd7ca39c72 --- /dev/null +++ b/indra/newview/llpanelwearing.cpp @@ -0,0 +1,263 @@ +/** + * @file llpanelwearing.cpp + * @brief List of agent's worn items. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelwearing.h" + +#include "llappearancemgr.h" +#include "llinventorymodel.h" +#include "llinventoryobserver.h" +#include "llsidetray.h" +#include "llviewermenu.h" +#include "llwearableitemslist.h" + +// Context menu and Gear menu helper. +static void edit_outfit() +{ + LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit")); +} + +////////////////////////////////////////////////////////////////////////// + +class LLWearingGearMenu +{ +public: + LLWearingGearMenu() + : mMenu(NULL) + { + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("Gear.Edit", boost::bind(&edit_outfit)); + + mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>( + "menu_wearing_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + llassert(mMenu); + } + + void show(LLView* spawning_view) + { + if (!mMenu) return; + + mMenu->buildDrawLabels(); + mMenu->updateParent(LLMenuGL::sMenuContainer); + S32 menu_x = 0; + S32 menu_y = spawning_view->getRect().getHeight() + mMenu->getRect().getHeight(); + LLMenuGL::showPopup(spawning_view, mMenu, menu_x, menu_y); + } + +private: + LLMenuGL* mMenu; +}; + +////////////////////////////////////////////////////////////////////////// + +class LLWearingContextMenu : public LLListContextMenu +{ +protected: + /* virtual */ LLContextMenu* createMenu() + { + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + functor_t take_off = boost::bind(&LLAppearanceMgr::removeItemFromAvatar, LLAppearanceMgr::getInstance(), _1); + + registrar.add("Wearing.Edit", boost::bind(&edit_outfit)); + registrar.add("Wearing.TakeOff", boost::bind(handleMultiple, take_off, mUUIDs)); + registrar.add("Wearing.Detach", boost::bind(handleMultiple, take_off, mUUIDs)); + + LLContextMenu* menu = createFromFile("menu_wearing_tab.xml"); + + updateMenuItemsVisibility(menu); + + return menu; + } + + void updateMenuItemsVisibility(LLContextMenu* menu) + { + bool bp_selected = false; // true if body parts selected + bool clothes_selected = false; + bool attachments_selected = false; + + // See what types of wearables are selected. + for (uuid_vec_t::const_iterator it = mUUIDs.begin(); it != mUUIDs.end(); ++it) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + + if (!item) + { + llwarns << "Invalid item" << llendl; + continue; + } + + LLAssetType::EType type = item->getType(); + if (type == LLAssetType::AT_CLOTHING) + { + clothes_selected = true; + } + else if (type == LLAssetType::AT_BODYPART) + { + bp_selected = true; + } + else if (type == LLAssetType::AT_OBJECT) + { + attachments_selected = true; + } + } + + // Enable/disable some menu items depending on the selection. + bool allow_detach = !bp_selected && !clothes_selected && attachments_selected; + bool allow_take_off = !bp_selected && clothes_selected && !attachments_selected; + + menu->setItemVisible("take_off", allow_take_off); + menu->setItemVisible("detach", allow_detach); + menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach); + } +}; + +////////////////////////////////////////////////////////////////////////// + +std::string LLPanelAppearanceTab::sFilterSubString = LLStringUtil::null; + +static LLRegisterPanelClassWrapper<LLPanelWearing> t_panel_wearing("panel_wearing"); + +LLPanelWearing::LLPanelWearing() + : LLPanelAppearanceTab() + , mCOFItemsList(NULL) + , mIsInitialized(false) +{ + mCategoriesObserver = new LLInventoryCategoriesObserver(); + + mGearMenu = new LLWearingGearMenu(); + mContextMenu = new LLWearingContextMenu(); +} + +LLPanelWearing::~LLPanelWearing() +{ + delete mGearMenu; + delete mContextMenu; + + if (gInventory.containsObserver(mCategoriesObserver)) + { + gInventory.removeObserver(mCategoriesObserver); + delete mCategoriesObserver; + } +} + +BOOL LLPanelWearing::postBuild() +{ + mCOFItemsList = getChild<LLWearableItemsList>("cof_items_list"); + mCOFItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onWearableItemsListRightClick, this, _1, _2, _3)); + + return TRUE; +} + +//virtual +void LLPanelWearing::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 cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + + // *TODO: I'm not sure is this check necessary but it never match while developing. + LLViewerInventoryCategory* category = gInventory.getCategory(cof); + if (!category) + return; + + gInventory.addObserver(mCategoriesObserver); + + // Start observing changes in Current Outfit category. + mCategoriesObserver->addCategory(cof, boost::bind(&LLWearableItemsList::updateList, mCOFItemsList, cof)); + + // Fetch Current Outfit 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(); + + mCOFItemsList->updateList(cof); + + mIsInitialized = true; + } +} + +// virtual +void LLPanelWearing::setFilterSubString(const std::string& string) +{ + sFilterSubString = string; + mCOFItemsList->setFilterSubString(sFilterSubString); +} + +// virtual +bool LLPanelWearing::isActionEnabled(const LLSD& userdata) +{ + const std::string command_name = userdata.asString(); + + if (command_name == "save_outfit") + { + bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked(); + bool outfit_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty(); + // allow save only if outfit isn't locked and is dirty + return !outfit_locked && outfit_dirty; + } + return false; +} + +// virtual +void LLPanelWearing::showGearMenu(LLView* spawning_view) +{ + if (!mGearMenu) return; + mGearMenu->show(spawning_view); +} + +boost::signals2::connection LLPanelWearing::setSelectionChangeCallback(commit_callback_t cb) +{ + if (!mCOFItemsList) return boost::signals2::connection(); + + return mCOFItemsList->setCommitCallback(cb); +} + +void LLPanelWearing::onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y) +{ + LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl); + if (!list) return; + + uuid_vec_t selected_uuids; + + list->getSelectedUUIDs(selected_uuids); + + mContextMenu->show(ctrl, selected_uuids, x, y); +} + +// EOF |