commit
5405bf10cd
|
|
@ -2031,6 +2031,39 @@ void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)
|
|||
}
|
||||
}
|
||||
|
||||
bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool closer_to_body)
|
||||
{
|
||||
if (!item) return false;
|
||||
if (!item->isWearableType()) return false;
|
||||
|
||||
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(item->getWearableType());
|
||||
if (wearable_iter == mWearableDatas.end()) return false;
|
||||
|
||||
wearableentry_vec_t& wearable_vec = wearable_iter->second;
|
||||
if (wearable_vec.empty()) return false;
|
||||
|
||||
const LLUUID& asset_id = item->getAssetUUID();
|
||||
|
||||
//nowhere to move if the wearable is already on any boundary (closest to the body/furthest from the body)
|
||||
if (closer_to_body && asset_id == wearable_vec.front()->getAssetID()) return false;
|
||||
if (!closer_to_body && asset_id == wearable_vec.back()->getAssetID()) return false;
|
||||
|
||||
for (U32 i = 0; i < wearable_vec.size(); ++i)
|
||||
{
|
||||
LLWearable* wearable = wearable_vec[i];
|
||||
if (!wearable) continue;
|
||||
if (wearable->getAssetID() != asset_id) continue;
|
||||
|
||||
//swapping wearables
|
||||
U32 swap_i = closer_to_body ? i-1 : i+1;
|
||||
wearable_vec[i] = wearable_vec[swap_i];
|
||||
wearable_vec[swap_i] = wearable;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLAgentWearables::updateServer()
|
||||
{
|
||||
sendAgentWearablesUpdate();
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ public:
|
|||
|
||||
void animateAllWearableParams(F32 delta, BOOL upload_bake);
|
||||
|
||||
bool moveWearable(const LLViewerInventoryItem* item, bool closer_to_body);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Accessors
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -122,6 +122,38 @@ private:
|
|||
bool mAppend;
|
||||
};
|
||||
|
||||
|
||||
//Inventory callback updating "dirty" state when destroyed
|
||||
class LLUpdateDirtyState: public LLInventoryCallback
|
||||
{
|
||||
public:
|
||||
LLUpdateDirtyState() {}
|
||||
virtual ~LLUpdateDirtyState(){ LLAppearanceMgr::getInstance()->updateIsDirty(); }
|
||||
virtual void fire(const LLUUID&) {}
|
||||
};
|
||||
|
||||
|
||||
//Inventory collect functor collecting wearables of a specific wearable type
|
||||
class LLFindClothesOfType : public LLInventoryCollectFunctor
|
||||
{
|
||||
public:
|
||||
LLFindClothesOfType(EWearableType type) : mWearableType(type) {}
|
||||
virtual ~LLFindClothesOfType() {}
|
||||
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
||||
{
|
||||
if (!item) return false;
|
||||
if (item->getType() != LLAssetType::AT_CLOTHING) return false;
|
||||
|
||||
LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item);
|
||||
if (!vitem || vitem->getWearableType() != mWearableType) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const EWearableType mWearableType;
|
||||
};
|
||||
|
||||
|
||||
LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy():
|
||||
mFireCount(0)
|
||||
{
|
||||
|
|
@ -1593,8 +1625,11 @@ bool LLAppearanceMgr::updateBaseOutfit()
|
|||
// in a Base Outfit we do not remove items, only links
|
||||
purgeCategory(base_outfit_id, false);
|
||||
|
||||
|
||||
LLPointer<LLInventoryCallback> dirty_state_updater = new LLUpdateDirtyState();
|
||||
|
||||
//COF contains only links so we copy to the Base Outfit only links
|
||||
shallowCopyCategoryContents(getCOF(), base_outfit_id, NULL);
|
||||
shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1802,6 +1837,62 @@ void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body)
|
||||
{
|
||||
if (!item || !item->isWearableType()) return false;
|
||||
if (item->getType() != LLAssetType::AT_CLOTHING) return false;
|
||||
if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false;
|
||||
|
||||
LLInventoryModel::cat_array_t cats;
|
||||
LLInventoryModel::item_array_t items;
|
||||
gInventory.collectDescendentsIf(getCOF(), cats, items, true, LLFindClothesOfType(item->getWearableType()));
|
||||
if (items.empty()) return false;
|
||||
|
||||
//*TODO all items are not guarantied to have valid descriptions (check?)
|
||||
std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType()));
|
||||
|
||||
if (closer_to_body && items.front() == item) return false;
|
||||
if (!closer_to_body && items.back() == item) return false;
|
||||
|
||||
LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item);
|
||||
if (items.end() == it) return false;
|
||||
|
||||
|
||||
//swapping descriptions
|
||||
closer_to_body ? --it : ++it;
|
||||
LLViewerInventoryItem* swap_item = *it;
|
||||
if (!swap_item) return false;
|
||||
std::string tmp = swap_item->LLInventoryItem::getDescription();
|
||||
swap_item->setDescription(item->LLInventoryItem::getDescription());
|
||||
item->setDescription(tmp);
|
||||
|
||||
|
||||
//items need to be updated on a dataserver
|
||||
item->setComplete(TRUE);
|
||||
item->updateServer(FALSE);
|
||||
gInventory.updateItem(item);
|
||||
|
||||
swap_item->setComplete(TRUE);
|
||||
swap_item->updateServer(FALSE);
|
||||
gInventory.updateItem(swap_item);
|
||||
|
||||
//to cause appearance of the agent to be updated
|
||||
bool result = false;
|
||||
if (result = gAgentWearables.moveWearable(item, closer_to_body))
|
||||
{
|
||||
gAgentAvatarp->wearableUpdated(item->getWearableType(), TRUE);
|
||||
}
|
||||
|
||||
setOutfitDirty(true);
|
||||
|
||||
//*TODO do we need to notify observers here in such a way?
|
||||
gInventory.notifyObservers();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//#define DUMP_CAT_VERBOSE
|
||||
|
||||
void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg)
|
||||
|
|
|
|||
|
|
@ -141,6 +141,8 @@ public:
|
|||
|
||||
LLUUID makeNewOutfitLinks(const std::string& new_folder_name);
|
||||
|
||||
bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body);
|
||||
|
||||
protected:
|
||||
LLAppearanceMgr();
|
||||
~LLAppearanceMgr();
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ const U64 WEARABLE_MASK = (1LL << LLInventoryType::IT_WEARABLE);
|
|||
const U64 ATTACHMENT_MASK = (1LL << LLInventoryType::IT_ATTACHMENT) | (1LL << LLInventoryType::IT_OBJECT);
|
||||
const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
|
||||
|
||||
static const std::string SAVE_BTN("save_btn");
|
||||
static const std::string REVERT_BTN("revert_btn");
|
||||
|
||||
class LLInventoryLookObserver : public LLInventoryObserver
|
||||
{
|
||||
public:
|
||||
|
|
@ -221,10 +224,9 @@ BOOL LLPanelOutfitEdit::postBuild()
|
|||
mEditWearableBtn->setVisible(FALSE);
|
||||
mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this));
|
||||
|
||||
childSetAction("revert_btn", boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
|
||||
childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
|
||||
|
||||
childSetAction("save_btn", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false));
|
||||
childSetAction("save_as_btn", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, true));
|
||||
childSetAction(SAVE_BTN, boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false));
|
||||
childSetAction("save_flyout_btn", boost::bind(&LLPanelOutfitEdit::showSaveMenu, this));
|
||||
|
||||
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar;
|
||||
|
|
@ -234,10 +236,22 @@ BOOL LLPanelOutfitEdit::postBuild()
|
|||
|
||||
mWearableListManager = new LLFilteredWearableListManager(
|
||||
getChild<LLInventoryItemsList>("filtered_wearables_list"), ALL_ITEMS_MASK);
|
||||
|
||||
childSetAction("move_closer_btn", boost::bind(&LLPanelOutfitEdit::moveWearable, this, true));
|
||||
childSetAction("move_further_btn", boost::bind(&LLPanelOutfitEdit::moveWearable, this, false));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLPanelOutfitEdit::moveWearable(bool closer_to_body)
|
||||
{
|
||||
LLViewerInventoryItem* wearable_to_move = gInventory.getItem(mLookContents->getSelectionInterface()->getCurrentID());
|
||||
LLAppearanceMgr::getInstance()->moveWearable(wearable_to_move, closer_to_body);
|
||||
|
||||
//*TODO why not to listen to inventory?
|
||||
updateLookInfo();
|
||||
}
|
||||
|
||||
void LLPanelOutfitEdit::showAddWearablesPanel()
|
||||
{
|
||||
childSetVisible("add_wearables_panel", childGetValue("add_btn"));
|
||||
|
|
@ -267,6 +281,8 @@ void LLPanelOutfitEdit::saveOutfit(bool as_new)
|
|||
{
|
||||
panel_outfits_inventory->onSave();
|
||||
}
|
||||
|
||||
//*TODO how to get to know when base outfit is updated or new outfit is created?
|
||||
}
|
||||
|
||||
void LLPanelOutfitEdit::showSaveMenu()
|
||||
|
|
@ -542,10 +558,12 @@ void LLPanelOutfitEdit::lookFetched(void)
|
|||
columns[0]["value"] = item->getName();
|
||||
columns[1]["column"] = "look_item_sort";
|
||||
columns[1]["type"] = "text"; // TODO: multi-wearable sort "type" should go here.
|
||||
columns[1]["value"] = "BAR"; // TODO: Multi-wearable sort index should go here
|
||||
columns[1]["value"] = item->LLInventoryItem::getDescription();
|
||||
|
||||
mLookContents->addElement(row);
|
||||
}
|
||||
|
||||
updateVerbs();
|
||||
}
|
||||
|
||||
void LLPanelOutfitEdit::updateLookInfo()
|
||||
|
|
@ -589,4 +607,15 @@ void LLPanelOutfitEdit::displayCurrentOutfit()
|
|||
updateLookInfo();
|
||||
}
|
||||
|
||||
//private
|
||||
void LLPanelOutfitEdit::updateVerbs()
|
||||
{
|
||||
bool outfit_is_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty();
|
||||
|
||||
childSetEnabled(SAVE_BTN, outfit_is_dirty);
|
||||
childSetEnabled(REVERT_BTN, outfit_is_dirty);
|
||||
|
||||
mSaveMenu->setItemEnabled("save_outfit", outfit_is_dirty);
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ public:
|
|||
// Sends a request for data about the given parcel, which will
|
||||
// only update the location if there is none already available.
|
||||
|
||||
void moveWearable(bool closer_to_body);
|
||||
|
||||
void showAddWearablesPanel();
|
||||
void showWearablesFilter();
|
||||
void showFilteredWearablesPanel();
|
||||
|
|
@ -110,6 +112,8 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
void updateVerbs();
|
||||
|
||||
//*TODO got rid of mCurrentOutfitID
|
||||
LLUUID mCurrentOutfitID;
|
||||
|
||||
|
|
|
|||
|
|
@ -221,6 +221,30 @@
|
|||
name="new_btn"
|
||||
top="1"
|
||||
width="31" />
|
||||
<button
|
||||
follows="bottom|left"
|
||||
height="25"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_overlay="Movement_Forward_On"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
layout="topleft"
|
||||
left_pad="1"
|
||||
name="move_closer_btn"
|
||||
top="1"
|
||||
width="31" />
|
||||
<button
|
||||
follows="bottom|left"
|
||||
height="25"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_overlay="Movement_Backward_On"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
layout="topleft"
|
||||
left_pad="1"
|
||||
name="move_further_btn"
|
||||
top="1"
|
||||
width="31" />
|
||||
<button
|
||||
follows="bottom|right"
|
||||
height="25"
|
||||
|
|
|
|||
Loading…
Reference in New Issue