partial implementation of EXT-6723 Create specialized view of inventory for "clothing" accordion tab of outfit editor
- added grouping clothing items by wearable type (shirt, jeans etc.) - added sorting clothing items by wearing order in groups - added separators between items of the same wearable type (lists: clothing, body parts) - added list specific button bars - partially added dummy items for missing wearable types in the COF (clothing list) Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/322 --HG-- branch : product-enginemeow-7.2.2
parent
8e0a73f0ed
commit
f9a120e898
|
|
@ -1092,7 +1092,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF()
|
|||
}
|
||||
|
||||
//preparing the list of wearables in the correct order for LLAgentWearables
|
||||
std::sort(wear_items.begin(), wear_items.end(), sort_by_description);
|
||||
sortItemsByActualDescription(wear_items);
|
||||
|
||||
|
||||
LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
|
||||
|
||||
|
|
@ -1910,6 +1911,13 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b
|
|||
return result;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items)
|
||||
{
|
||||
if (items.size() < 2) return;
|
||||
|
||||
std::sort(items.begin(), items.end(), sort_by_description);
|
||||
}
|
||||
|
||||
//#define DUMP_CAT_VERBOSE
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
|
|||
friend class LLSingleton<LLAppearanceMgr>;
|
||||
|
||||
public:
|
||||
typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t;
|
||||
|
||||
void updateAppearanceFromCOF();
|
||||
bool needToSaveCOF();
|
||||
void updateCOF(const LLUUID& category, bool append = false);
|
||||
|
|
@ -143,17 +145,17 @@ public:
|
|||
|
||||
bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body);
|
||||
|
||||
static void sortItemsByActualDescription(LLInventoryModel::item_array_t& items);
|
||||
|
||||
//Divvy items into arrays by wearable type
|
||||
static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type);
|
||||
|
||||
protected:
|
||||
LLAppearanceMgr();
|
||||
~LLAppearanceMgr();
|
||||
|
||||
private:
|
||||
|
||||
typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t;
|
||||
|
||||
//Divvy items into arrays by wearable type
|
||||
static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type);
|
||||
|
||||
//Check ordering information on wearables stored in links' descriptions and update if it is invalid
|
||||
void updateClothingOrderingInfo();
|
||||
|
||||
|
|
|
|||
|
|
@ -94,48 +94,140 @@ void LLCOFWearables::refresh()
|
|||
clear();
|
||||
|
||||
LLInventoryModel::cat_array_t cats;
|
||||
LLInventoryModel::item_array_t items;
|
||||
|
||||
gInventory.collectDescendents(LLAppearanceMgr::getInstance()->getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH);
|
||||
if (items.empty()) return;
|
||||
LLInventoryModel::item_array_t cof_items;
|
||||
|
||||
for (U32 i = 0; i < items.size(); ++i)
|
||||
gInventory.collectDescendents(LLAppearanceMgr::getInstance()->getCOF(), cats, cof_items, LLInventoryModel::EXCLUDE_TRASH);
|
||||
|
||||
populateAttachmentsAndBodypartsLists(cof_items);
|
||||
|
||||
|
||||
LLAppearanceMgr::wearables_by_type_t clothing_by_type(WT_COUNT);
|
||||
LLAppearanceMgr::getInstance()->divvyWearablesByType(cof_items, clothing_by_type);
|
||||
|
||||
populateClothingList(clothing_by_type);
|
||||
}
|
||||
|
||||
|
||||
void LLCOFWearables::populateAttachmentsAndBodypartsLists(const LLInventoryModel::item_array_t& cof_items)
|
||||
{
|
||||
for (U32 i = 0; i < cof_items.size(); ++i)
|
||||
{
|
||||
LLViewerInventoryItem* item = items.get(i);
|
||||
LLViewerInventoryItem* item = cof_items.get(i);
|
||||
if (!item) continue;
|
||||
|
||||
const LLAssetType::EType item_type = item->getType();
|
||||
if (item_type == LLAssetType::AT_CLOTHING) continue;
|
||||
|
||||
LLPanelInventoryListItem* item_panel = LLPanelInventoryListItem::createItemPanel(item);
|
||||
if (!item_panel) continue;
|
||||
|
||||
switch (item->getType())
|
||||
if (item_type == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
case LLAssetType::AT_OBJECT:
|
||||
mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
|
||||
break;
|
||||
|
||||
case LLAssetType::AT_BODYPART:
|
||||
mBodyParts->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
|
||||
break;
|
||||
|
||||
case LLAssetType::AT_CLOTHING:
|
||||
mClothing->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
|
||||
}
|
||||
else if (item_type == LLAssetType::AT_BODYPART)
|
||||
{
|
||||
mBodyParts->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
|
||||
addWearableTypeSeparator(mBodyParts);
|
||||
}
|
||||
}
|
||||
|
||||
mAttachments->sort(); //*TODO by Name
|
||||
mAttachments->notify(REARRANGE); //notifying the parent about the list's size change (cause items were added with rearrange=false)
|
||||
|
||||
mClothing->sort(); //*TODO by actual inventory item description
|
||||
mClothing->notify(REARRANGE);
|
||||
|
||||
mBodyParts->sort(); //*TODO by name
|
||||
if (mAttachments->size())
|
||||
{
|
||||
mAttachments->sort(); //*TODO by Name
|
||||
mAttachments->notify(REARRANGE); //notifying the parent about the list's size change (cause items were added with rearrange=false)
|
||||
}
|
||||
|
||||
if (mBodyParts->size())
|
||||
{
|
||||
mBodyParts->sort(); //*TODO by name
|
||||
}
|
||||
|
||||
addListButtonBar(mBodyParts, "panel_bodyparts_list_button_bar.xml");
|
||||
mBodyParts->notify(REARRANGE);
|
||||
}
|
||||
|
||||
|
||||
void LLCOFWearables::populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type)
|
||||
{
|
||||
llassert(clothing_by_type.size() == WT_COUNT);
|
||||
|
||||
addListButtonBar(mClothing, "panel_clothing_list_button_bar.xml");
|
||||
|
||||
for (U32 type = WT_SHIRT; type < WT_COUNT; ++type)
|
||||
{
|
||||
U32 size = clothing_by_type[type].size();
|
||||
if (!size) continue;
|
||||
|
||||
LLAppearanceMgr::sortItemsByActualDescription(clothing_by_type[type]);
|
||||
|
||||
for (U32 i = 0; i < size; i++)
|
||||
{
|
||||
LLViewerInventoryItem* item = clothing_by_type[type][i];
|
||||
|
||||
LLPanelInventoryListItem* item_panel = LLPanelInventoryListItem::createItemPanel(item);
|
||||
if (!item_panel) continue;
|
||||
|
||||
mClothing->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
|
||||
}
|
||||
|
||||
addWearableTypeSeparator(mClothing);
|
||||
}
|
||||
|
||||
addClothingTypesDummies(clothing_by_type);
|
||||
|
||||
mClothing->notify(REARRANGE);
|
||||
}
|
||||
|
||||
void LLCOFWearables::addListButtonBar(LLFlatListView* list, std::string xml_filename)
|
||||
{
|
||||
llassert(list);
|
||||
llassert(xml_filename.length());
|
||||
|
||||
LLPanel::Params params;
|
||||
LLPanel* button_bar = LLUICtrlFactory::create<LLPanel>(params);
|
||||
LLUICtrlFactory::instance().buildPanel(button_bar, xml_filename);
|
||||
|
||||
LLRect rc = button_bar->getRect();
|
||||
button_bar->reshape(list->getItemsRect().getWidth(), rc.getHeight());
|
||||
|
||||
list->addItem(button_bar, LLUUID::null, ADD_TOP, false);
|
||||
}
|
||||
|
||||
//adding dummy items for missing wearable types
|
||||
void LLCOFWearables::addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type)
|
||||
{
|
||||
llassert(clothing_by_type.size() == WT_COUNT);
|
||||
|
||||
for (U32 type = WT_SHIRT; type < WT_COUNT; type++)
|
||||
{
|
||||
U32 size = clothing_by_type[type].size();
|
||||
if (size) continue;
|
||||
|
||||
//*TODO create dummy item panel
|
||||
|
||||
//*TODO add dummy item panel -> mClothing->addItem(dummy_item_panel, item->getUUID(), ADD_BOTTOM, false);
|
||||
|
||||
addWearableTypeSeparator(mClothing);
|
||||
}
|
||||
}
|
||||
|
||||
void LLCOFWearables::addWearableTypeSeparator(LLFlatListView* list)
|
||||
{
|
||||
llassert(list);
|
||||
|
||||
static LLXMLNodePtr separator_xml_node = getXMLNode("panel_wearable_type_separator.xml");
|
||||
if (separator_xml_node->isNull()) return;
|
||||
|
||||
LLPanel* separator = LLUICtrlFactory::defaultBuilder<LLPanel>(separator_xml_node, NULL, NULL);
|
||||
|
||||
LLRect rc = separator->getRect();
|
||||
rc.setOriginAndSize(0, 0, list->getItemsRect().getWidth(), rc.getHeight());
|
||||
separator->setRect(rc);
|
||||
|
||||
list->addItem(separator, LLUUID::null, ADD_BOTTOM, false);
|
||||
}
|
||||
|
||||
LLUUID LLCOFWearables::getSelectedUUID()
|
||||
{
|
||||
if (!mLastSelectedList) return LLUUID::null;
|
||||
|
|
@ -150,4 +242,17 @@ void LLCOFWearables::clear()
|
|||
mBodyParts->clear();
|
||||
}
|
||||
|
||||
LLXMLNodePtr LLCOFWearables::getXMLNode(std::string xml_filename)
|
||||
{
|
||||
LLXMLNodePtr xmlNode = NULL;
|
||||
bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, xmlNode);
|
||||
if (!success)
|
||||
{
|
||||
llwarning("Failed to read xml", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return xmlNode;
|
||||
}
|
||||
|
||||
//EOF
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
#define LL_LLCOFWEARABLES_H
|
||||
|
||||
#include "llpanel.h"
|
||||
#include "llinventorymodel.h"
|
||||
#include "llappearancemgr.h"
|
||||
|
||||
class LLFlatListView;
|
||||
|
||||
|
|
@ -52,8 +54,16 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
void populateAttachmentsAndBodypartsLists(const LLInventoryModel::item_array_t& cof_items);
|
||||
void populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type);
|
||||
|
||||
void addListButtonBar(LLFlatListView* list, std::string xml_filename);
|
||||
void addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type);
|
||||
void addWearableTypeSeparator(LLFlatListView* list);
|
||||
void onSelectionChange(LLFlatListView* selected_list);
|
||||
|
||||
LLXMLNodePtr LLCOFWearables::getXMLNode(std::string xml_filename);
|
||||
|
||||
LLFlatListView* mAttachments;
|
||||
LLFlatListView* mClothing;
|
||||
LLFlatListView* mBodyParts;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
|
||||
<panel
|
||||
follows="left|right|top"
|
||||
height="35"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="clothing_list_button_bar_panel"
|
||||
top="0"
|
||||
visible="true"
|
||||
width="300">
|
||||
<button
|
||||
follows="top|left"
|
||||
height="25"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
label="Switch"
|
||||
layout="topleft"
|
||||
left="5"
|
||||
name="switch_btn"
|
||||
top="5"
|
||||
width="45" />
|
||||
<button
|
||||
follows="top|right"
|
||||
height="25"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
label="Shop >"
|
||||
layout="topleft"
|
||||
right="-5"
|
||||
name="bodyparts_shop_btn"
|
||||
top="5"
|
||||
width="61" />
|
||||
</panel>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
|
||||
<panel
|
||||
follows="left|right|top"
|
||||
height="35"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="clothing_list_button_bar_panel"
|
||||
top="0"
|
||||
visible="true"
|
||||
width="500">
|
||||
<button
|
||||
follows="top|left"
|
||||
height="25"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
is_toggle="true"
|
||||
label="Add +"
|
||||
layout="topleft"
|
||||
left="5"
|
||||
name="add_btn"
|
||||
top="5"
|
||||
width="45" />
|
||||
<button
|
||||
follows="top|right"
|
||||
height="25"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
label="Shop >"
|
||||
layout="topleft"
|
||||
right="-5"
|
||||
name="clothing_shop_btn"
|
||||
top="5"
|
||||
width="61" />
|
||||
</panel>
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
height="373"
|
||||
layout="topleft"
|
||||
left="3"
|
||||
single_expansion="true"
|
||||
top="0"
|
||||
name="cof_wearables_accordion"
|
||||
background_visible="true"
|
||||
|
|
|
|||
Loading…
Reference in New Issue