diff options
Diffstat (limited to 'indra')
27 files changed, 728 insertions, 776 deletions
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 2433c14315..c7463e581c 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -50,14 +50,21 @@ LLFlatListView::Params::Params() allow_select("allow_select"), multi_select("multi_select"), keep_one_selected("keep_one_selected"), + keep_selection_visible_on_reshape("keep_selection_visible_on_reshape",false), no_items_text("no_items_text") {}; void LLFlatListView::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) { + S32 delta = height - getRect().getHeight(); LLScrollContainer::reshape(width, height, called_from_parent); setItemsNoScrollWidth(width); rearrangeItems(); + + if(delta!= 0 && mKeepSelectionVisibleOnReshape) + { + ensureSelectedVisible(); + } } const LLRect& LLFlatListView::getItemsRect() const @@ -380,6 +387,7 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) , mPrevNotifyParentRect(LLRect()) , mNoItemsCommentTextbox(NULL) , mIsConsecutiveSelection(false) + , mKeepSelectionVisibleOnReshape(p.keep_selection_visible_on_reshape) { mBorderThickness = getBorderWidth(); diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index f4e0426f15..0820a7ab67 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -105,6 +105,9 @@ public: /** don't allow to deselect all selected items (for mouse events on items only) */ Optional<bool> keep_one_selected; + /** try to keep selection visible after reshape */ + Optional<bool> keep_selection_visible_on_reshape; + /** padding between items */ Optional<U32> item_pad; @@ -412,6 +415,8 @@ private: bool mIsConsecutiveSelection; + bool mKeepSelectionVisibleOnReshape; + /** All pairs of the list */ pairs_list_t mItemPairs; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c1b2d680be..ce42cb6038 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -363,6 +363,7 @@ set(viewer_SOURCE_FILES llpaneltopinfobar.cpp llpanelvolume.cpp llpanelvolumepulldown.cpp + llpanelwearing.cpp llparcelselection.cpp llparticipantlist.cpp llpatchvertexarray.cpp @@ -830,6 +831,7 @@ set(viewer_HEADER_FILES lloutfitslist.h lloutfitobserver.h lloutputmonitorctrl.h + llpanelappearancetab.h llpanelavatar.h llpanelavatartag.h llpanelblockedlist.h @@ -883,6 +885,7 @@ set(viewer_HEADER_FILES llpaneltopinfobar.h llpanelvolume.h llpanelvolumepulldown.h + llpanelwearing.h llparcelselection.h llparticipantlist.h llpatchvertexarray.h diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 5728256dba..017fcf6e2b 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -48,7 +48,6 @@ #include "llmd5.h" #include "llnotificationsutil.h" #include "lloutfitobserver.h" -#include "llpaneloutfitsinventory.h" #include "llsidepanelappearance.h" #include "llsidetray.h" #include "lltexlayer.h" @@ -1232,45 +1231,6 @@ void LLAgentWearables::createStandardWearablesAllDone() gAgentAvatarp->onFirstTEMessageReceived(); } - -class LLShowCreatedOutfit: public LLInventoryCallback -{ -public: - LLShowCreatedOutfit(LLUUID& folder_id): - mFolderID(folder_id) - { - } - - virtual ~LLShowCreatedOutfit() - { - LLSD key; - LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key); - LLPanelOutfitsInventory *outfit_panel = - dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory")); - // TODO: add handling "My Outfits" tab. - if (outfit_panel && outfit_panel->isCOFPanelActive()) - { - outfit_panel->getRootFolder()->clearSelection(); - outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE); - } - LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0; - if (tab_outfits && !tab_outfits->getDisplayChildren()) - { - tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren()); - } - - LLAppearanceMgr::instance().updateIsDirty(); - LLAppearanceMgr::instance().updatePanelOutfitName(""); - } - - virtual void fire(const LLUUID&) - { - } - -private: - LLUUID mFolderID; -}; - void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) { LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type, index); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 3947be49bb..597076503d 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -45,7 +45,7 @@ #include "llinventoryobserver.h" #include "llnotificationsutil.h" #include "lloutfitobserver.h" -#include "llpaneloutfitsinventory.h" +#include "lloutfitslist.h" #include "llselectmgr.h" #include "llsidepanelappearance.h" #include "llsidetray.h" @@ -1697,9 +1697,10 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category, void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append) { - gAgentWearables.notifyLoadingStarted(); if(!category) return; + gAgentWearables.notifyLoadingStarted(); + llinfos << "wearInventoryCategory( " << category->getName() << " )" << llendl; @@ -2305,18 +2306,11 @@ public: { LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key); } - LLPanelOutfitsInventory *outfit_panel = - dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory")); - if (outfit_panel) - { - outfit_panel->getRootFolder()->clearSelection(); - outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE); - } - - LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0; - if (tab_outfits && !tab_outfits->getDisplayChildren()) + LLOutfitsList *outfits_list = + dynamic_cast<LLOutfitsList*>(LLSideTray::getInstance()->getPanel("outfitslist_tab")); + if (outfits_list) { - tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren()); + outfits_list->setSelectedOutfitByUUID(mFolderID); } LLAppearanceMgr::getInstance()->updateIsDirty(); diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index ab4ff1bcfc..61779d5c0e 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -34,10 +34,12 @@ #define LL_LLAPPEARANCEMGR_H #include "llsingleton.h" + +#include "llagentwearables.h" +#include "llcallbacklist.h" #include "llinventorymodel.h" #include "llinventoryobserver.h" #include "llviewerinventory.h" -#include "llcallbacklist.h" class LLWearable; class LLWearableHoldingPattern; @@ -360,6 +362,9 @@ public: << llendl; //dec_busy_count(); gInventory.removeObserver(this); + + // lets notify observers that loading is finished. + gAgentWearables.notifyLoadingFinished(); delete this; return; } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index afaeddaaeb..a5f24c55fe 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -72,7 +72,6 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llwearablelist.h" -#include "llpaneloutfitsinventory.h" typedef std::pair<LLUUID, LLUUID> two_uuids_t; typedef std::list<two_uuids_t> two_uuids_list_t; @@ -511,17 +510,6 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, { const LLInventoryObject *obj = getInventoryObject(); - bool is_sidepanel = isInOutfitsSidePanel(); - if (is_sidepanel) - { - // Sidepanel includes restricted menu. - if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID)) - { - items.push_back(std::string("Remove Link")); - } - return; - } - if (obj) { if (obj->getIsLinkType()) @@ -948,16 +936,6 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) } } -BOOL LLInvFVBridge::isInOutfitsSidePanel() const -{ - LLInventoryPanel *my_panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get()); - LLPanelOutfitsInventory *outfit_panel = - dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory")); - if (!outfit_panel) - return FALSE; - return outfit_panel->isTabPanel(my_panel); -} - BOOL LLInvFVBridge::canShare() const { const LLInventoryModel* model = getInventoryModel(); @@ -2430,17 +2408,8 @@ void LLFolderBridge::folderOptionsMenu() const bool is_ensemble = (type == LLFolderType::FT_NONE || LLFolderType::lookupIsEnsembleType(type)); - // calling card related functionality for folders. - - const bool is_sidepanel = isInOutfitsSidePanel(); - if (is_sidepanel) - { - mItems.push_back("Rename"); - addDeleteContextMenuOptions(mItems, disabled_items); - } - // Only enable calling-card related options for non-system folders. - if (!is_sidepanel && !is_system_folder) + if (!is_system_folder) { LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard)) @@ -2469,10 +2438,7 @@ void LLFolderBridge::folderOptionsMenu() checkFolderForContentsOfType(model, is_object) || checkFolderForContentsOfType(model, is_gesture) ) { - if (!is_sidepanel) - { - mItems.push_back(std::string("Folder Wearables Separator")); - } + mItems.push_back(std::string("Folder Wearables Separator")); // Only enable add/replace outfit for non-system folders. if (!is_system_folder) @@ -3763,13 +3729,6 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Share")); } - bool is_sidepanel = isInOutfitsSidePanel(); - - if (!is_sidepanel) - { - addOpenRightClickMenuOption(items); - items.push_back(std::string("Properties")); - } getClipboardEntries(true, items, disabled_items, flags); @@ -4071,12 +4030,8 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Share")); } - bool is_sidepanel = isInOutfitsSidePanel(); - if (!is_sidepanel) - { - items.push_back(std::string("Properties")); - } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -4431,24 +4386,17 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Share")); } - bool is_sidepanel = isInOutfitsSidePanel(); - if (can_open && !is_sidepanel) + if (can_open) { addOpenRightClickMenuOption(items); } - if (!is_sidepanel) - { - items.push_back(std::string("Properties")); - } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); - if (!is_sidepanel) - { - items.push_back(std::string("Wearable Separator")); - } + items.push_back(std::string("Wearable Separator")); items.push_back(std::string("Wearable Edit")); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 64d0f8d254..97e87c2f3b 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -74,7 +74,6 @@ public: U32 flags = 0x00); virtual ~LLInvFVBridge() {} - BOOL isInOutfitsSidePanel() const; // allow context menus to be customized for side panel BOOL canShare() const; //-------------------------------------------------------------------- diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 6542afc366..b8489d450b 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -70,7 +70,148 @@ bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LL ////////////////////////////////////////////////////////////////////////// -class OutfitContextMenu : public LLListContextMenu +class LLOutfitListGearMenu +{ +public: + LLOutfitListGearMenu(LLOutfitsList* olist) + : mOutfitList(olist), + mMenu(NULL) + { + llassert_always(mOutfitList); + + 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(&LLOutfitListGearMenu::onDelete, this)); + registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenu::onCreate, this, _2)); + + enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitsList::isActionEnabled, mOutfitList, _2)); + enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenu::onVisible, this, _2)); + + mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>( + "menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + llassert(mMenu); + } + + void show(LLView* spawning_view) + { + if (!mMenu) return; + + updateItemsVisibility(); + 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); + } + + void updateItemsVisibility() + { + if (!mMenu) return; + + bool have_selection = getSelectedOutfitID().notNull(); + mMenu->setItemVisible("sepatator1", have_selection); + mMenu->setItemVisible("sepatator2", have_selection); + mMenu->arrangeAndClear(); // update menu height + } + +private: + const LLUUID& getSelectedOutfitID() + { + return mOutfitList->getSelectedOutfitUUID(); + } + + LLViewerInventoryCategory* getSelectedOutfit() + { + const LLUUID& selected_outfit_id = getSelectedOutfitID(); + if (selected_outfit_id.isNull()) + { + return NULL; + } + + LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id); + return cat; + } + + void onWear() + { + LLViewerInventoryCategory* selected_outfit = getSelectedOutfit(); + if (selected_outfit) + { + LLAppearanceMgr::instance().wearInventoryCategory( + selected_outfit, /*copy=*/ FALSE, /*append=*/ FALSE); + } + } + + void onTakeOff() + { + const LLUUID& selected_outfit_id = getSelectedOutfitID(); + if (selected_outfit_id.notNull()) + { + LLAppearanceMgr::instance().takeOffOutfit(selected_outfit_id); + } + } + + void onRename() + { + const LLUUID& selected_outfit_id = getSelectedOutfitID(); + if (selected_outfit_id.notNull()) + { + LLAppearanceMgr::instance().renameOutfit(selected_outfit_id); + } + } + + void onDelete() + { + const LLUUID& selected_outfit_id = getSelectedOutfitID(); + if (selected_outfit_id.notNull()) + { + remove_category(&gInventory, selected_outfit_id); + } + } + + void onCreate(const LLSD& data) + { + LLWearableType::EType type = LLWearableType::typeNameToType(data.asString()); + if (type == LLWearableType::WT_NONE) + { + llwarns << "Invalid wearable type" << llendl; + return; + } + + LLAgentWearables::createWearable(type, true); + } + + bool 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; + } + + LLOutfitsList* mOutfitList; + LLMenuGL* mMenu; +}; + +////////////////////////////////////////////////////////////////////////// + +class LLOutfitContextMenu : public LLListContextMenu { protected: /* virtual */ LLContextMenu* createMenu() @@ -89,8 +230,8 @@ protected: registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id)); registrar.add("Outfit.Delete", boost::bind(deleteOutfit, selected_id)); - enable_registrar.add("Outfit.OnEnable", boost::bind(&OutfitContextMenu::onEnable, this, _2)); - enable_registrar.add("Outfit.OnVisible", boost::bind(&OutfitContextMenu::onVisible, this, _2)); + 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"); } @@ -103,8 +244,13 @@ protected: { return get_is_category_renameable(&gInventory, outfit_cat_id); } + else if ("wear_replace" == param) + { + return !gAgentWearables.isCOFChangeInProgress(); + } else if ("wear_add" == param) { + if (gAgentWearables.isCOFChangeInProgress()) return false; return LLAppearanceMgr::getCanAddToCOF(outfit_cat_id); } else if ("take_off" == param) @@ -157,7 +303,7 @@ protected: static LLRegisterPanelClassWrapper<LLOutfitsList> t_outfits_list("outfits_list"); LLOutfitsList::LLOutfitsList() - : LLPanel() + : LLPanelAppearanceTab() , mAccordion(NULL) , mListCommands(NULL) , mIsInitialized(false) @@ -165,11 +311,13 @@ LLOutfitsList::LLOutfitsList() { mCategoriesObserver = new LLInventoryCategoriesObserver(); - mOutfitMenu = new OutfitContextMenu(); + mGearMenu = new LLOutfitListGearMenu(this); + mOutfitMenu = new LLOutfitContextMenu(); } LLOutfitsList::~LLOutfitsList() { + delete mGearMenu; delete mOutfitMenu; if (gInventory.containsObserver(mCategoriesObserver)) @@ -308,7 +456,7 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) // If filter is currently applied we store the initial tab state and // open it to show matched items if any. - if (!mFilterSubString.empty()) + if (!sFilterSubString.empty()) { tab->notifyChildren(LLSD().with("action","store_state")); tab->setDisplayChildren(true); @@ -318,7 +466,7 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) // filter to the newly added list. list->setForceRefresh(true); - list->setFilterSubString(mFilterSubString); + list->setFilterSubString(sFilterSubString); } } @@ -410,14 +558,84 @@ void LLOutfitsList::performAction(std::string action) } } +void LLOutfitsList::removeSelected() +{ + if (mSelectedOutfitUUID.notNull()) + { + remove_category(&gInventory, mSelectedOutfitUUID); + } +} + +void LLOutfitsList::setSelectedOutfitByUUID(const LLUUID& outfit_uuid) +{ + for (outfits_map_t::iterator iter = mOutfitsMap.begin(); + iter != mOutfitsMap.end(); + ++iter) + { + if (outfit_uuid == iter->first) + { + LLAccordionCtrlTab* tab = iter->second; + if (!tab) continue; + + LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView()); + if (!list) continue; + + tab->setFocus(TRUE); + changeOutfitSelection(list, outfit_uuid); + + tab->setDisplayChildren(true); + } + } +} + +// virtual void LLOutfitsList::setFilterSubString(const std::string& string) { applyFilter(string); - mFilterSubString = string; + sFilterSubString = string; +} + +// virtual +bool LLOutfitsList::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); + } + if (command_name == "rename") + { + return get_is_category_renameable(&gInventory, mSelectedOutfitUUID); + } + 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; + } + if (command_name == "wear") + { + return !gAgentWearables.isCOFChangeInProgress(); + } + if (command_name == "take_off") + { + return LLAppearanceMgr::getInstance()->getBaseOutfitUUID() == mSelectedOutfitUUID; + } + return false; +} + +// virtual +void LLOutfitsList::showGearMenu(LLView* spawning_view) +{ + if (!mGearMenu) return; + mGearMenu->show(spawning_view); } -boost::signals2::connection LLOutfitsList::addSelectionChangeCallback(selection_change_callback_t cb) +boost::signals2::connection LLOutfitsList::setSelectionChangeCallback(selection_change_callback_t cb) { return mSelectionChangeSignal.connect(cb); } @@ -553,7 +771,7 @@ void LLOutfitsList::restoreOutfitSelection(LLAccordionCtrlTab* tab, const LLUUID void LLOutfitsList::onFilteredWearableItemsListRefresh(LLUICtrl* ctrl) { - if (!ctrl || mFilterSubString.empty()) + if (!ctrl || sFilterSubString.empty()) return; for (outfits_map_t::iterator @@ -567,7 +785,7 @@ void LLOutfitsList::onFilteredWearableItemsListRefresh(LLUICtrl* ctrl) LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView()); if (list != ctrl) continue; - applyFilterToTab(iter->first, tab, mFilterSubString); + applyFilterToTab(iter->first, tab, sFilterSubString); } } @@ -583,7 +801,7 @@ void LLOutfitsList::applyFilter(const std::string& new_filter_substring) LLAccordionCtrlTab* tab = iter->second; if (!tab) continue; - bool more_restrictive = mFilterSubString.size() < new_filter_substring.size() && !new_filter_substring.substr(0, mFilterSubString.size()).compare(mFilterSubString); + bool more_restrictive = sFilterSubString.size() < new_filter_substring.size() && !new_filter_substring.substr(0, sFilterSubString.size()).compare(sFilterSubString); // Restore tab visibility in case of less restrictive filter // to compare it with updated string if it was previously hidden. @@ -598,7 +816,7 @@ void LLOutfitsList::applyFilter(const std::string& new_filter_substring) list->setFilterSubString(new_filter_substring); } - if(mFilterSubString.empty() && !new_filter_substring.empty()) + if(sFilterSubString.empty() && !new_filter_substring.empty()) { //store accordion tab state when filter is not empty tab->notifyChildren(LLSD().with("action","store_state")); @@ -696,7 +914,7 @@ void LLOutfitsList::onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y) uuid_vec_t selected_uuids; - // Collect seleted items from all selected lists. + // Collect selected items from all selected lists. for (wearables_lists_map_t::iterator iter = mSelectedListsMap.begin(); iter != mSelectedListsMap.end(); ++iter) diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index a6b9a66836..d207624792 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -37,12 +37,15 @@ // newview #include "llinventorymodel.h" -#include "llinventoryobserver.h" +#include "llpanelappearancetab.h" class LLAccordionCtrlTab; +class LLInventoryCategoriesObserver; +class LLOutfitListGearMenu; class LLWearableItemsList; class LLListContextMenu; + /** * @class LLOutfitTabNameComparator * @@ -66,9 +69,9 @@ public: * which displays each outfit in an accordion tab with a flat list * of items inside it. * - * Starts fetching nevessary inventory content on first openning. + * Starts fetching necessary inventory content on first opening. */ -class LLOutfitsList : public LLPanel +class LLOutfitsList : public LLPanelAppearanceTab { public: typedef boost::function<void (const LLUUID&)> selection_change_callback_t; @@ -88,11 +91,19 @@ public: void performAction(std::string action); - void setFilterSubString(const std::string& string); + void removeSelected(); + + void setSelectedOutfitByUUID(const LLUUID& outfit_uuid); + + /*virtual*/ void setFilterSubString(const std::string& string); + + /*virtual*/ bool isActionEnabled(const LLSD& userdata); + + /*virtual*/ void showGearMenu(LLView* spawning_view); const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; } - boost::signals2::connection addSelectionChangeCallback(selection_change_callback_t cb); + boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb); /** * Returns true if there is a selection inside currently selected outfit @@ -184,13 +195,12 @@ private: LLUUID mHighlightedOutfitUUID; selection_change_signal_t mSelectionChangeSignal; - std::string mFilterSubString; - typedef std::map<LLUUID, LLAccordionCtrlTab*> outfits_map_t; typedef outfits_map_t::value_type outfits_map_value_t; outfits_map_t mOutfitsMap; - LLListContextMenu* mOutfitMenu; + LLOutfitListGearMenu* mGearMenu; + LLListContextMenu* mOutfitMenu; bool mIsInitialized; /** diff --git a/indra/newview/llpanelappearancetab.h b/indra/newview/llpanelappearancetab.h index c2f8dbd074..f1901a63a4 100644 --- a/indra/newview/llpanelappearancetab.h +++ b/indra/newview/llpanelappearancetab.h @@ -1,6 +1,6 @@ /** - * @file llpanelplacestab.h - * @brief Tabs interface for Side Bar "Places" panel + * @file llpanelappearancetab.h + * @brief Tabs interface for Side Bar "My Appearance" panel * * $LicenseInfo:firstyear=2009&license=viewergpl$ * @@ -34,28 +34,22 @@ #include "llpanel.h" -#include "llpanelappearance.h" - class LLPanelAppearanceTab : public LLPanel { public: - LLPanelAppearanceTab(LLPanelAppearance *parent) : - LLPanel(), - mParent(parent) - {} + LLPanelAppearanceTab() : LLPanel() {} virtual ~LLPanelAppearanceTab() {} - virtual void onSearchEdit(const std::string& string) = 0; - virtual void updateVerbs() = 0; // Updates buttons at the bottom of Appearance panel - virtual void onWear() = 0; - virtual void onEdit() = 0; - virtual void onNew() = 0; + virtual void setFilterSubString(const std::string& string) = 0; + + virtual bool isActionEnabled(const LLSD& userdata) = 0; - bool isTabVisible(); // Check if parent TabContainer is visible. + virtual void showGearMenu(LLView* spawning_view) = 0; + static const std::string& getFilterSubString() { return sFilterSubString; } protected: - LLPanelAppearance* mParent; + static std::string sFilterSubString; }; #endif //LL_LLPANELAPPEARANCETAB_H diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index d382c77430..2f1cad8a75 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -33,216 +33,32 @@ #include "llpaneloutfitsinventory.h" -#include "llagent.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" +#include "llnotificationsutil.h" +#include "lltabcontainer.h" -#include "llbutton.h" -#include "llfloaterreg.h" -#include "llfloaterworldmap.h" -#include "llfloaterinventory.h" -#include "llfoldervieweventlistener.h" -#include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" -#include "llinventorypanel.h" -#include "lllandmark.h" -#include "lllineeditor.h" -#include "llmodaldialog.h" -#include "llnotificationsutil.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" #include "lloutfitobserver.h" #include "lloutfitslist.h" +#include "llpanelwearing.h" #include "llsaveoutfitcombobtn.h" #include "llsidepanelappearance.h" #include "llsidetray.h" -#include "lltabcontainer.h" #include "llviewerfoldertype.h" -#include "llviewerjointattachment.h" -#include "llvoavatarself.h" - -// List Commands -#include "lldndbutton.h" -#include "llmenugl.h" -#include "llviewermenu.h" - -#include "llviewercontrol.h" static const std::string OUTFITS_TAB_NAME = "outfitslist_tab"; static const std::string COF_TAB_NAME = "cof_tab"; static LLRegisterPanelClassWrapper<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory"); -class LLOutfitListGearMenu -{ -public: - LLOutfitListGearMenu(LLOutfitsList* olist) - : mOutfitList(olist), - mMenu(NULL) - { - llassert_always(mOutfitList); - - 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(&LLOutfitListGearMenu::onDelete, this)); - registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenu::onCreate, this, _2)); - - 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<LLMenuGL>( - "menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - llassert(mMenu); - } - - LLMenuGL* getMenu() { return mMenu; } - - void show(LLView* spawning_view) - { - if (!mMenu) return; - - updateItemsVisibility(); - 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); - } - - void updateItemsVisibility() - { - if (!mMenu) return; - - bool have_selection = getSelectedOutfitID().notNull(); - mMenu->setItemVisible("sepatator1", have_selection); - mMenu->setItemVisible("sepatator2", have_selection); - mMenu->arrangeAndClear(); // update menu height - } - -private: - const LLUUID& getSelectedOutfitID() - { - return mOutfitList->getSelectedOutfitUUID(); - } - - LLViewerInventoryCategory* getSelectedOutfit() - { - const LLUUID& selected_outfit_id = getSelectedOutfitID(); - if (selected_outfit_id.isNull()) - { - return NULL; - } - - LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id); - return cat; - } - - void onWear() - { - LLViewerInventoryCategory* selected_outfit = getSelectedOutfit(); - if (selected_outfit) - { - LLAppearanceMgr::instance().wearInventoryCategory( - selected_outfit, /*copy=*/ FALSE, /*append=*/ FALSE); - } - } - - void onTakeOff() - { - const LLUUID& selected_outfit_id = getSelectedOutfitID(); - if (selected_outfit_id.notNull()) - { - LLAppearanceMgr::instance().takeOffOutfit(selected_outfit_id); - } - } - - void onRename() - { - const LLUUID& selected_outfit_id = getSelectedOutfitID(); - if (selected_outfit_id.notNull()) - { - LLAppearanceMgr::instance().renameOutfit(selected_outfit_id); - } - } - - void onDelete() - { - const LLUUID& selected_outfit_id = getSelectedOutfitID(); - if (selected_outfit_id.notNull()) - { - remove_category(&gInventory, selected_outfit_id); - } - } - - void onCreate(const LLSD& data) - { - LLWearableType::EType type = LLWearableType::typeNameToType(data.asString()); - if (type == LLWearableType::WT_NONE) - { - llwarns << "Invalid wearable type" << llendl; - return; - } - - LLAgentWearables::createWearable(type, true); - } - - bool onEnable(LLSD::String param) - { - const LLUUID& selected_outfit_id = getSelectedOutfitID(); - if (selected_outfit_id.isNull()) // no selection or invalid outfit selected - { - return false; - } - - if ("rename" == param) - { - return get_is_category_renameable(&gInventory, selected_outfit_id); - } - else if ("delete" == param) - { - return LLAppearanceMgr::instance().getCanRemoveOutfit(selected_outfit_id); - } - else if ("take_off" == param) - { - return LLAppearanceMgr::getCanRemoveFromCOF(selected_outfit_id); - } - - return true; - } - - bool onVisible(LLSD::String param) - { - const LLUUID& selected_outfit_id = getSelectedOutfitID(); - if (selected_outfit_id.isNull()) // no selection or invalid outfit selected - { - return false; - } - - bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id; - - if ("wear" == param) - { - return !is_worn; - } - - return true; - } - - LLOutfitsList* mOutfitList; - LLMenuGL* mMenu; -}; - LLPanelOutfitsInventory::LLPanelOutfitsInventory() : mMyOutfitsPanel(NULL), mCurrentOutfitPanel(NULL), - mGearMenu(NULL), + mActivePanel(NULL), mInitialized(false) { - mSavedFolderState = new LLSaveFolderState(); - mSavedFolderState->setApply(FALSE); gAgentWearables.addLoadedCallback(boost::bind(&LLPanelOutfitsInventory::onWearablesLoaded, this)); gAgentWearables.addLoadingStartedCallback(boost::bind(&LLPanelOutfitsInventory::onWearablesLoading, this)); @@ -254,8 +70,6 @@ LLPanelOutfitsInventory::LLPanelOutfitsInventory() : LLPanelOutfitsInventory::~LLPanelOutfitsInventory() { - delete mGearMenu; - delete mSavedFolderState; } // virtual @@ -297,7 +111,8 @@ void LLPanelOutfitsInventory::onOpen(const LLSD& key) // and update verbs. onTabChange(); - // Auto open the first outfit newly created so new users can see sample outfit contents + // *TODO: Auto open the first outfit newly created so new users can see sample outfit contents + /* static bool should_open_outfit = true; if (should_open_outfit && gAgent.isFirstLogin()) { @@ -317,6 +132,7 @@ void LLPanelOutfitsInventory::onOpen(const LLSD& key) } } should_open_outfit = false; + */ } void LLPanelOutfitsInventory::updateVerbs() @@ -330,93 +146,30 @@ void LLPanelOutfitsInventory::updateVerbs() // virtual void LLPanelOutfitsInventory::onSearchEdit(const std::string& string) { - mFilterSubString = string; + if (!mActivePanel) return; - // TODO: add handling "My Outfits" tab. - if (!isCOFPanelActive()) - { - mMyOutfitsPanel->setFilterSubString(string); - return; - } + mFilterSubString = string; if (string == "") { - getActivePanel()->setFilterSubString(LLStringUtil::null); - - // re-open folders that were initially open - mSavedFolderState->setApply(TRUE); - getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - LLOpenFoldersWithSelection opener; - getRootFolder()->applyFunctorRecursively(opener); - getRootFolder()->scrollToShowSelection(); + mActivePanel->setFilterSubString(LLStringUtil::null); } LLInventoryModelBackgroundFetch::instance().start(); - if (getActivePanel()->getFilterSubString().empty() && string.empty()) + if (mActivePanel->getFilterSubString().empty() && string.empty()) { // current filter and new filter empty, do nothing return; } - // save current folder open state if no filter currently applied - if (getRootFolder()->getFilterSubString().empty()) - { - mSavedFolderState->setApply(FALSE); - getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - } - // set new filter string - getActivePanel()->setFilterSubString(string); + mActivePanel->setFilterSubString(string); } void LLPanelOutfitsInventory::onWearButtonClick() { - // TODO: Remove if/else, add common interface - // for "My Outfits" and "Wearing" tabs. - if (!isCOFPanelActive()) - { - mMyOutfitsPanel->performAction("replaceoutfit"); - } - else - { - LLFolderViewEventListener* listenerp = getCorrectListenerForAction(); - if (listenerp) - { - listenerp->performAction(NULL, "replaceoutfit"); - } - } -} - -void LLPanelOutfitsInventory::onAdd() -{ - // TODO: Remove if/else, add common interface - // for "My Outfits" and "Wearing" tabs. - if (!isCOFPanelActive()) - { - mMyOutfitsPanel->performAction("addtooutfit"); - } - else - { - LLFolderViewEventListener* listenerp = getCorrectListenerForAction(); - if (listenerp) - { - listenerp->performAction(NULL, "addtooutfit"); - } - } -} - -void LLPanelOutfitsInventory::onRemove() -{ - LLFolderViewEventListener* listenerp = getCorrectListenerForAction(); - if (listenerp) - { - listenerp->performAction(NULL, "removefromoutfit"); - } -} - -void LLPanelOutfitsInventory::onEdit() -{ + mMyOutfitsPanel->performAction("replaceoutfit"); } bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD& response) @@ -446,8 +199,6 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD& return false; } - - void LLPanelOutfitsInventory::onSave() { std::string outfit_name; @@ -475,57 +226,6 @@ void LLPanelOutfitsInventory::onSave() }*/ } -void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action) -{ - updateVerbs(); - - // TODO: add handling "My Outfits" tab. - if (!isCOFPanelActive()) - return; - - if (getRootFolder()->needsAutoRename() && items.size()) - { - getRootFolder()->startRenamingSelectedItem(); - getRootFolder()->setNeedsAutoRename(FALSE); - } -} - -LLFolderViewEventListener *LLPanelOutfitsInventory::getCorrectListenerForAction() -{ - // TODO: add handling "My Outfits" tab. - if (!isCOFPanelActive()) - return NULL; - - LLFolderViewItem* current_item = getRootFolder()->getCurSelectedItem(); - if (!current_item) - return NULL; - - LLFolderViewEventListener* listenerp = current_item->getListener(); - if (getIsCorrectType(listenerp)) - { - return listenerp; - } - return NULL; -} - -bool LLPanelOutfitsInventory::getIsCorrectType(const LLFolderViewEventListener *listenerp) const -{ - if (listenerp->getInventoryType() == LLInventoryType::IT_CATEGORY) - { - LLViewerInventoryCategory *cat = gInventory.getCategory(listenerp->getUUID()); - if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT) - { - return true; - } - } - return false; -} - -LLFolderView *LLPanelOutfitsInventory::getRootFolder() -{ - return getActivePanel()->getRootFolder(); -} - //static LLPanelOutfitsInventory* LLPanelOutfitsInventory::findInstance() { @@ -542,21 +242,12 @@ void LLPanelOutfitsInventory::initListCommandsHandlers() mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelOutfitsInventory::showGearMenu, this)); mListCommands->childSetAction("trash_btn", boost::bind(&LLPanelOutfitsInventory::onTrashButtonClick, this)); mListCommands->childSetAction("wear_btn", boost::bind(&LLPanelOutfitsInventory::onWearButtonClick, this)); - - LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>("trash_btn"); - trash_btn->setDragAndDropHandler(boost::bind(&LLPanelOutfitsInventory::handleDragAndDropToTrash, this - , _4 // BOOL drop - , _5 // EDragAndDropType cargo_type - , _7 // EAcceptance* accept - )); - - mGearMenu = new LLOutfitListGearMenu(mMyOutfitsPanel); } void LLPanelOutfitsInventory::updateListCommands() { bool trash_enabled = isActionEnabled("delete"); - bool wear_enabled = !gAgentWearables.isCOFChangeInProgress() && isActionEnabled("wear"); + bool wear_enabled = isActionEnabled("wear"); bool wear_visible = !isCOFPanelActive(); bool make_outfit_enabled = isActionEnabled("save_outfit"); @@ -568,269 +259,58 @@ void LLPanelOutfitsInventory::updateListCommands() void LLPanelOutfitsInventory::showGearMenu() { - if (!mGearMenu) return; + if (!mActivePanel) return; LLView* spawning_view = getChild<LLView>("options_gear_btn"); - mGearMenu->show(spawning_view); + mActivePanel->showGearMenu(spawning_view); } void LLPanelOutfitsInventory::onTrashButtonClick() { - onClipboardAction("delete"); -} + mMyOutfitsPanel->removeSelected(); -void LLPanelOutfitsInventory::onClipboardAction(const LLSD& userdata) -{ - std::string command_name = userdata.asString(); - if (isCOFPanelActive()) - { - getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name); - } - else // "My Outfits" tab active - { - if (command_name == "delete") - { - const LLUUID& selected_outfit_id = mMyOutfitsPanel->getSelectedOutfitUUID(); - if (selected_outfit_id.notNull()) - { - remove_category(&gInventory, selected_outfit_id); - } - } - else - { - llwarns << "Unrecognized action" << llendl; - } - } - updateListCommands(); - updateVerbs(); + updateListCommands(); + updateVerbs(); } -void LLPanelOutfitsInventory::onCustomAction(const LLSD& userdata) +bool LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata) { - if (!isActionEnabled(userdata)) - return; - - const std::string command_name = userdata.asString(); - if (command_name == "new") - { - onSave(); - } - if (command_name == "edit") - { - onEdit(); - } - if (command_name == "wear") - { - onWearButtonClick(); - } - // Note: This option has been removed from the gear menu. - if (command_name == "add") - { - onAdd(); - } - if (command_name == "remove") - { - onRemove(); - } - if (command_name == "rename") - { - onClipboardAction("rename"); - } - if (command_name == "remove_link") - { - onClipboardAction("delete"); - } - if (command_name == "delete") - { - onClipboardAction("delete"); - } - updateListCommands(); - updateVerbs(); + return mActivePanel && mActivePanel->isActionEnabled(userdata); } - -BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata) -{ - const std::string command_name = userdata.asString(); - if (command_name == "delete" || command_name == "remove") - { - BOOL can_delete = FALSE; - - if (isCOFPanelActive()) - { - LLFolderView* root = getActivePanel()->getRootFolder(); - if (root) - { - std::set<LLUUID> selection_set = root->getSelectionList(); - can_delete = (selection_set.size() > 0); - for (std::set<LLUUID>::iterator iter = selection_set.begin(); - iter != selection_set.end(); - ++iter) - { - const LLUUID &item_id = (*iter); - LLFolderViewItem *item = root->getItemByID(item_id); - can_delete &= item->getListener()->isItemRemovable(); - } - } - } - else // "My Outfits" tab active - { - const LLUUID& selected_outfit = mMyOutfitsPanel->getSelectedOutfitUUID(); - // first condition prevents trash btn from enabling when items are selected inside outfit (EXT-7847) - can_delete = !mMyOutfitsPanel->hasItemSelected() && LLAppearanceMgr::instance().getCanRemoveOutfit(selected_outfit); - } - - return can_delete; - } - if (command_name == "remove_link") - { - BOOL can_delete = FALSE; - LLFolderView* root = getActivePanel()->getRootFolder(); - if (root) - { - std::set<LLUUID> selection_set = root->getSelectionList(); - can_delete = (selection_set.size() > 0); - for (std::set<LLUUID>::iterator iter = selection_set.begin(); - iter != selection_set.end(); - ++iter) - { - const LLUUID &item_id = (*iter); - LLViewerInventoryItem *item = gInventory.getItem(item_id); - if (!item || !item->getIsLinkType()) - return FALSE; - } - return can_delete; - } - return FALSE; - } - if (command_name == "rename" || - command_name == "delete_outfit") - { - return (getCorrectListenerForAction() != NULL) && hasItemsSelected(); - } - - if (command_name == "wear") - { - if (isCOFPanelActive()) - { - return FALSE; - } - return hasItemsSelected(); - } - 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; - } - - if (command_name == "edit" || - command_name == "add" - ) - { - return (getCorrectListenerForAction() != NULL); - } - return TRUE; -} - -bool LLPanelOutfitsInventory::hasItemsSelected() -{ - bool has_items_selected = false; - - if (isCOFPanelActive()) - { - LLFolderView* root = getActivePanel()->getRootFolder(); - if (root) - { - std::set<LLUUID> selection_set = root->getSelectionList(); - has_items_selected = (selection_set.size() > 0); - } - } - else // My Outfits Tab is active - { - has_items_selected = mMyOutfitsPanel->getSelectedOutfitUUID().notNull(); - } - return has_items_selected; -} - -bool LLPanelOutfitsInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept) -{ - *accept = ACCEPT_NO; - - const bool is_enabled = isActionEnabled("delete"); - if (is_enabled) *accept = ACCEPT_YES_MULTI; - - if (is_enabled && drop) - { - onClipboardAction("delete"); - } - return true; -} - -// List Commands // -//////////////////////////////////////////////////////////////////////////////// +// List Commands // +////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// -// Tab panels // +// Tab panels // void LLPanelOutfitsInventory::initTabPanels() { - mCurrentOutfitPanel = getChild<LLInventoryPanel>(COF_TAB_NAME); - mCurrentOutfitPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mCurrentOutfitPanel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, mCurrentOutfitPanel, _1, _2)); + mCurrentOutfitPanel = getChild<LLPanelWearing>(COF_TAB_NAME); + mCurrentOutfitPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); mMyOutfitsPanel = getChild<LLOutfitsList>(OUTFITS_TAB_NAME); - mMyOutfitsPanel->addSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); + mMyOutfitsPanel->setSelectionChangeCallback(boost::bind(&LLPanelOutfitsInventory::updateVerbs, this)); mAppearanceTabs = getChild<LLTabContainer>("appearance_tabs"); mAppearanceTabs->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::onTabChange, this)); } -void LLPanelOutfitsInventory::onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action) -{ - if (user_action && items.size() > 0) - { - // TODO: add handling "My Outfits" tab. - if (isCOFPanelActive()) - { - onSelectionChange(items, user_action); - } - else - { - mCurrentOutfitPanel->getRootFolder()->clearSelection(); - } - } -} - void LLPanelOutfitsInventory::onTabChange() { - // TODO: add handling "My Outfits" tab. - if (isCOFPanelActive()) - { - mCurrentOutfitPanel->setFilterSubString(mFilterSubString); - } - else - { - mMyOutfitsPanel->setFilterSubString(mFilterSubString); - mMyOutfitsPanel->onOpen(LLSD()); - } + mActivePanel = dynamic_cast<LLPanelAppearanceTab*>(mAppearanceTabs->getCurrentPanel()); + if (!mActivePanel) return; + + mActivePanel->setFilterSubString(mFilterSubString); + mActivePanel->onOpen(LLSD()); updateVerbs(); } -BOOL LLPanelOutfitsInventory::isTabPanel(LLInventoryPanel *panel) const +bool LLPanelOutfitsInventory::isCOFPanelActive() const { - // TODO: add handling "My Outfits" tab. - if (mCurrentOutfitPanel == panel) - { - return TRUE; - } - return FALSE; -} + if (!mActivePanel) return false; -BOOL LLPanelOutfitsInventory::isCOFPanelActive() const -{ - return (childGetVisibleTab("appearance_tabs")->getName() == COF_TAB_NAME); + return mActivePanel->getName() == COF_TAB_NAME; } void LLPanelOutfitsInventory::setWearablesLoading(bool val) diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index eabfda7f8c..a50e047140 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -34,20 +34,15 @@ #define LL_LLPANELOUTFITSINVENTORY_H #include "llpanel.h" -#include "llinventoryobserver.h" -class LLFolderView; -class LLFolderViewItem; -class LLFolderViewEventListener; -class LLInventoryPanel; class LLOutfitsList; -class LLSaveFolderState; -class LLButton; +class LLOutfitListGearMenu; +class LLPanelAppearanceTab; +class LLPanelWearing; class LLMenuGL; class LLSidepanelAppearance; class LLTabContainer; class LLSaveOutfitComboBtn; -class LLOutfitListGearMenu; class LLPanelOutfitsInventory : public LLPanel { @@ -60,55 +55,36 @@ public: /*virtual*/ void onOpen(const LLSD& key); void onSearchEdit(const std::string& string); - void onAdd(); - void onRemove(); - void onEdit(); void onSave(); bool onSaveCommit(const LLSD& notification, const LLSD& response); - void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action); - - // If a compatible listener type is selected, then return a pointer to that. - // Otherwise, return NULL. - LLFolderViewEventListener* getCorrectListenerForAction(); - - LLFolderView* getRootFolder(); static LLSidepanelAppearance* getAppearanceSP(); static LLPanelOutfitsInventory* findInstance(); protected: void updateVerbs(); - bool getIsCorrectType(const LLFolderViewEventListener *listenerp) const; private: - LLSaveFolderState* mSavedFolderState; LLTabContainer* mAppearanceTabs; std::string mFilterSubString; std::auto_ptr<LLSaveOutfitComboBtn> mSaveComboBtn; -public: - ////////////////////////////////////////////////////////////////////////////////// - // tab panels - // TODO: change getActivePanel() to return the active tab instead of returning - // a pointer to "Wearing" inventory panel. - LLInventoryPanel* getActivePanel() { return mCurrentOutfitPanel; } - - BOOL isTabPanel(LLInventoryPanel *panel) const; - BOOL isCOFPanelActive() const; + ////////////////////////////////////////////////////////////////////////////////// + // tab panels // protected: void initTabPanels(); - void onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action); void onTabChange(); + bool isCOFPanelActive() const; private: + LLPanelAppearanceTab* mActivePanel; LLOutfitsList* mMyOutfitsPanel; - LLInventoryPanel* mCurrentOutfitPanel; + LLPanelWearing* mCurrentOutfitPanel; - // tab panels // - //////////////////////////////////////////////////////////////////////////////// - + // tab panels // + ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// // List Commands // @@ -118,21 +94,15 @@ protected: void onWearButtonClick(); void showGearMenu(); void onTrashButtonClick(); - void onClipboardAction(const LLSD& userdata); - BOOL isActionEnabled(const LLSD& command_name); - void onCustomAction(const LLSD& command_name); - bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept); - bool hasItemsSelected(); + bool isActionEnabled(const LLSD& userdata); void setWearablesLoading(bool val); void onWearablesLoaded(); void onWearablesLoading(); private: LLPanel* mListCommands; - LLOutfitListGearMenu* mGearMenu; LLMenuGL* mMenuAdd; - // List Commands // - //////////////////////////////////////////////////////////////////////////////// - /// + // List Commands // + ////////////////////////////////////////////////////////////////////////////////// bool mInitialized; }; diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp new file mode 100644 index 0000000000..b8852890ad --- /dev/null +++ b/indra/newview/llpanelwearing.cpp @@ -0,0 +1,214 @@ +/** + * @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; + + registrar.add("Wearing.Edit", boost::bind(&edit_outfit)); + + return createFromFile("menu_wearing_tab.xml"); + } +}; + +////////////////////////////////////////////////////////////////////////// + +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 diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h new file mode 100644 index 0000000000..1573990d13 --- /dev/null +++ b/indra/newview/llpanelwearing.h @@ -0,0 +1,81 @@ +/** + * @file llpanelwearing.h + * @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$ + */ + +#ifndef LL_LLPANELWEARING_H +#define LL_LLPANELWEARING_H + +#include "llpanel.h" + +// newview +#include "llpanelappearancetab.h" + +class LLInventoryCategoriesObserver; +class LLListContextMenu; +class LLWearableItemsList; +class LLWearingGearMenu; + +/** + * @class LLPanelWearing + * + * A list of agents's currently worn items represented by + * a flat list view. + * Starts fetching necessary inventory content on first opening. + */ +class LLPanelWearing : public LLPanelAppearanceTab +{ +public: + LLPanelWearing(); + virtual ~LLPanelWearing(); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void onOpen(const LLSD& info); + + /*virtual*/ void setFilterSubString(const std::string& string); + + /*virtual*/ bool isActionEnabled(const LLSD& userdata); + + /*virtual*/ void showGearMenu(LLView* spawning_view); + + boost::signals2::connection setSelectionChangeCallback(commit_callback_t cb); + +private: + void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y); + + LLInventoryCategoriesObserver* mCategoriesObserver; + LLWearableItemsList* mCOFItemsList; + LLWearingGearMenu* mGearMenu; + LLListContextMenu* mContextMenu; + + bool mIsInitialized; +}; + +#endif //LL_LLPANELWEARING_H diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index ff315d3c53..a7b4873fed 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -876,6 +876,7 @@ void LLPreviewGesture::onLoadComplete(LLVFS *vfs, self->mDirty = FALSE; self->refresh(); + self->refreshFromItem(); // to update description and title } else { diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 0d1be91125..ea5796d766 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -390,8 +390,8 @@ void LLSidepanelAppearance::refreshCurrentOutfitName(const std::string& name) return; } - std::string look_name = gAgentWearables.isCOFChangeInProgress() ? "" : getString("No Outfit"); - mCurrentLookName->setText(look_name); + std::string string_name = gAgentWearables.isCOFChangeInProgress() ? "Changing outfits" : "No Outfit"; + mCurrentLookName->setText(getString(string_name)); mOpenOutfitBtn->setEnabled(FALSE); } else @@ -475,6 +475,12 @@ void LLSidepanelAppearance::setWearablesLoading(bool val) { childSetVisible("wearables_loading_indicator", val); childSetVisible("edit_outfit_btn", !val); + + if (!val) + { + // refresh outfit name when COF is already changed. + refreshCurrentOutfitName(); + } } void LLSidepanelAppearance::showDefaultSubpart() diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 832d4a2fe6..da15b93697 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -95,19 +95,22 @@ LLPanelWearableListItem::LLPanelWearableListItem(LLViewerInventoryItem* item) ////////////////////////////////////////////////////////////////////////// // static -LLPanelWearableOutfitItem* LLPanelWearableOutfitItem::create(LLViewerInventoryItem* item) +LLPanelWearableOutfitItem* LLPanelWearableOutfitItem::create(LLViewerInventoryItem* item, + bool worn_indication_enabled) { LLPanelWearableOutfitItem* list_item = NULL; if (item) { - list_item = new LLPanelWearableOutfitItem(item); + list_item = new LLPanelWearableOutfitItem(item, worn_indication_enabled); list_item->init(); } return list_item; } -LLPanelWearableOutfitItem::LLPanelWearableOutfitItem(LLViewerInventoryItem* item) +LLPanelWearableOutfitItem::LLPanelWearableOutfitItem(LLViewerInventoryItem* item, + bool worn_indication_enabled) : LLPanelInventoryListItemBase(item) +, mWornIndicationEnabled(worn_indication_enabled) { } @@ -117,7 +120,7 @@ void LLPanelWearableOutfitItem::updateItem(const std::string& name, { std::string search_label = name; - if (get_is_item_worn(mInventoryItemUUID)) + if (mWornIndicationEnabled && get_is_item_worn(mInventoryItemUUID)) { search_label += LLTrans::getString("worn"); item_state = IS_WORN; @@ -444,6 +447,7 @@ static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_i LLWearableItemsList::Params::Params() : standalone("standalone", true) +, worn_indication_enabled("worn_indication_enabled", true) {} LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p) @@ -456,6 +460,7 @@ LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p) // Use built-in context menu. setRightMouseDownCallback(boost::bind(&LLWearableItemsList::onRightClick, this, _2, _3)); } + mWornIndicationEnabled = p.worn_indication_enabled; } // virtual @@ -471,7 +476,7 @@ void LLWearableItemsList::addNewItem(LLViewerInventoryItem* item, bool rearrange llassert(item != NULL); } - LLPanelWearableOutfitItem *list_item = LLPanelWearableOutfitItem::create(item); + LLPanelWearableOutfitItem *list_item = LLPanelWearableOutfitItem::create(item, mWornIndicationEnabled); if (!list_item) return; @@ -657,7 +662,7 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu setMenuItemVisible(menu, "wear_add", mask == MASK_CLOTHING && n_worn == 0); setMenuItemEnabled(menu, "wear_add", n_items == 1 && canAddWearable(ids.front())); setMenuItemVisible(menu, "wear", n_worn == 0); - setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART)); + setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items); setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1 && n_items == 1); setMenuItemVisible(menu, "create_new", mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1); setMenuItemVisible(menu, "show_original", !standalone); diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index 2bfb90e3ec..eb82418454 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -82,7 +82,8 @@ class LLPanelWearableOutfitItem : public LLPanelInventoryListItemBase { LOG_CLASS(LLPanelWearableOutfitItem); public: - static LLPanelWearableOutfitItem* create(LLViewerInventoryItem* item); + static LLPanelWearableOutfitItem* create(LLViewerInventoryItem* item, + bool worn_indication_enabled); /** * Updates item name and (worn) suffix. @@ -91,7 +92,11 @@ public: EItemState item_state = IS_DEFAULT); protected: - LLPanelWearableOutfitItem(LLViewerInventoryItem* item); + LLPanelWearableOutfitItem(LLViewerInventoryItem* item, + bool worn_indication_enabled); + +private: + bool mWornIndicationEnabled; }; class LLPanelDeletableWearableListItem : public LLPanelWearableListItem @@ -352,6 +357,7 @@ public: struct Params : public LLInitParam::Block<Params, LLInventoryItemsList::Params> { Optional<bool> standalone; + Optional<bool> worn_indication_enabled; Params(); }; @@ -377,6 +383,7 @@ protected: void onRightClick(S32 x, S32 y); bool mIsStandalone; + bool mWornIndicationEnabled; }; #endif //LL_LLWEARABLEITEMSLIST_H diff --git a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml index 9c3151fe07..8c8bb29baf 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml @@ -8,6 +8,9 @@ name="wear_replace"> <on_click function="Outfit.WearReplace" /> + <on_enable + function="Outfit.OnEnable" + parameter="wear_replace" /> <on_visible function="Outfit.OnVisible" parameter="wear_replace" /> diff --git a/indra/newview/skins/default/xui/en/menu_wearing_gear.xml b/indra/newview/skins/default/xui/en/menu_wearing_gear.xml new file mode 100644 index 0000000000..84431a2f69 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_wearing_gear.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<menu + layout="topleft" + name="Gear Wearing"> + <menu_item_call + label="Edit Outfit" + layout="topleft" + name="edit"> + <on_click + function="Gear.Edit" /> + </menu_item_call> +</menu> diff --git a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml new file mode 100644 index 0000000000..85505f9972 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Wearing"> + <menu_item_call + label="Edit Outfit" + layout="topleft" + name="edit"> + <on_click + function="Wearing.Edit" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml index f016c27b0a..d2c8ab159f 100644 --- a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml +++ b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml @@ -31,6 +31,7 @@ item_pad="3" layout="topleft" left="0" + keep_selection_visible_on_reshape="true" multi_select="true" name="list_attachments" top="0" @@ -45,6 +46,7 @@ follows="all" height="10" item_pad="3" + keep_selection_visible_on_reshape="true" layout="topleft" left="0" multi_select="true" @@ -61,6 +63,7 @@ follows="all" height="10" item_pad="3" + keep_selection_visible_on_reshape="true" layout="topleft" left="0" multi_select="true" diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml index 1ab9f722d0..06255353a7 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml @@ -390,7 +390,7 @@ <button follows="bottomleft" height="23" - label="Revert" + label="Undo Changes" layout="topleft" left_pad="7" name="revert_button" 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 a59070496e..b365540d1f 100644 --- a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml @@ -34,22 +34,32 @@ follows="all" label="MY OUTFITS" layout="topleft" - width="315" /> - <inventory_panel - follows="all" + width="312" /> + <panel background_visible="true" - background_opaque="true" - label="WEARING" + class="panel_wearing" + follows="all" + height="490" help_topic="now_wearing_tab" - allow_multi_select="true" - border="false" - left="0" - top="0" - mouse_opaque="true" + label="WEARING" + layout="topleft" name="cof_tab" - start_folder="Current Outfit" - use_label_suffix="true" - width="315" /> + width="312"> + <wearable_items_list + allow_select="true" + follows="all" + height="490" + keep_one_selected="true" + left="1" + multi_select="true" + name="cof_items_list" + standalone="false" + top="0" + translate="false" + width="310" + worn_indication_enabled="false" + /> + </panel> </tab_container> <panel background_visible="true" @@ -84,7 +94,7 @@ width="241" /> - <dnd_button + <button follows="bottom|right" height="25" image_hover_unselected="Toolbar_Right_Over" diff --git a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml index e189d11d35..9a07d3a48a 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml @@ -21,6 +21,9 @@ width="333"> <string name="Now Wearing" value="Now wearing..." /> + <string + name="Changing outfits" + value="Changing outfits" /> <panel background_opaque="true" background_visible="true" diff --git a/indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml b/indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml index dbe1ea2874..49c2abe1a5 100644 --- a/indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml +++ b/indra/newview/skins/default/xui/en/widgets/inventory_list_item.xml @@ -14,5 +14,6 @@ <!-- style for inventory list item WORN on avatar --> <worn_style font="SansSerifSmall" - font.style="BOLD" /> + font.style="BOLD" + color="green" /> </inventory_list_item> |