--HG--
branch : product-engine
meow-7.2.2
Igor Borovkov 2010-04-23 14:45:27 +03:00
commit 5405bf10cd
7 changed files with 190 additions and 5 deletions

View File

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

View File

@ -82,6 +82,8 @@ public:
void animateAllWearableParams(F32 delta, BOOL upload_bake);
bool moveWearable(const LLViewerInventoryItem* item, bool closer_to_body);
//--------------------------------------------------------------------
// Accessors
//--------------------------------------------------------------------

View File

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

View File

@ -141,6 +141,8 @@ public:
LLUUID makeNewOutfitLinks(const std::string& new_folder_name);
bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body);
protected:
LLAppearanceMgr();
~LLAppearanceMgr();

View File

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

View File

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

View File

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