Initial version of Visual Outfit Browser

master
pavelkproductengine 2015-12-11 19:58:08 +02:00
parent 1be6320933
commit 6a02f5bbce
16 changed files with 2025 additions and 496 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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,74 +208,72 @@ public:
/*virtual*/ void onOpen(const LLSD& info);
void refreshList(const LLUUID& category_id);
//virtual void refreshList(const LLUUID& category_id);
/*virtual*/ void updateAddedCategory(LLUUID cat_id);
/*virtual*/ void updateRemovedCategory(LLUUID cat_id);
// highlits currently worn outfit tab text and unhighlights previously worn
void highlightBaseOutfit();
/*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id);
void performAction(std::string action);
//void performAction(std::string action);
void removeSelected();
void setSelectedOutfitByUUID(const LLUUID& outfit_uuid);
/*virtual*/ void setFilterSubString(const std::string& string);
/*virtual*/ bool isActionEnabled(const LLSD& userdata);
const LLUUID& getSelectedOutfitUUID() const { return mSelectedOutfitUUID; }
/*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; }
protected:
LLOutfitListGearMenuBase* createGearMenu();
private:
void onOutfitsRemovalConfirmation(const LLSD& notification, const LLSD& response);
/**
* Wrapper for LLCommonUtils::computeDifference. @see LLCommonUtils::computeDifference
*/
void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved);
//void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved);
void getCurrentCategories(uuid_vec_t& vcur);
/**
* Updates tab displaying outfit identified by category_id.
*/
void updateOutfitTab(const LLUUID& category_id);
/*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name);
/*virtual*/ void sortOutfits();
/*virtual*/ void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid);
/**
* Resets previous selection and stores newly selected list and outfit id.
*/
void changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
/*virtual*/ void onChangeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
/**
*Resets items selection inside outfit
*/
void resetItemSelection(LLWearableItemsList* list, const LLUUID& category_id);
/**
* Saves newly selected outfit ID.
*/
void setSelectedOutfitUUID(const LLUUID& category_id);
/**
* Removes the outfit from selection.
*/
@ -182,15 +309,16 @@ private:
*/
bool canWearSelected();
void onAccordionTabRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
void onCOFChanged();
void onSelectionChange(LLUICtrl* ctrl);
void onListSelectionChange(LLUICtrl* ctrl);
/*virtual*/ void onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
static void onOutfitRename(const LLSD& notification, const LLSD& response);
LLInventoryCategoriesObserver* mCategoriesObserver;
//LLInventoryCategoriesObserver* mCategoriesObserver;
LLAccordionCtrl* mAccordion;
LLPanel* mListCommands;
@ -199,11 +327,6 @@ private:
typedef wearables_lists_map_t::value_type wearables_lists_map_value_t;
wearables_lists_map_t mSelectedListsMap;
LLUUID mSelectedOutfitUUID;
// id of currently highlited outfit
LLUUID mHighlightedOutfitUUID;
selection_change_signal_t mSelectionChangeSignal;
typedef std::map<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
*/

View File

@ -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));
}

View File

@ -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 //

View File

@ -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);
}

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -32,6 +32,17 @@
halign="center"
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"