From fb1594535ec578d6601d54557ca5bf1a77c45351 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 2 Jun 2012 17:32:19 -0500 Subject: [PATCH] Intermediate step in refactoring appearance panel --- indra/llui/llscrollingpanellist.h | 12 +- indra/newview/CMakeLists.txt | 6 + indra/newview/llfloatercustomize.cpp | 1707 +------------------ indra/newview/llfloatercustomize.h | 1 - indra/newview/llpaneleditwearable.cpp | 1405 +++++++++++++++ indra/newview/llpaneleditwearable.h | 114 ++ indra/newview/llscrollingpanelparam.cpp | 329 ++++ indra/newview/llscrollingpanelparam.h | 76 + indra/newview/llscrollingpanelparambase.cpp | 139 ++ indra/newview/llscrollingpanelparambase.h | 61 + indra/newview/lltoolmorph.cpp | 9 +- indra/newview/llwearable.cpp | 43 + 12 files changed, 2201 insertions(+), 1701 deletions(-) create mode 100644 indra/newview/llpaneleditwearable.cpp create mode 100644 indra/newview/llpaneleditwearable.h create mode 100644 indra/newview/llscrollingpanelparam.cpp create mode 100644 indra/newview/llscrollingpanelparam.h create mode 100644 indra/newview/llscrollingpanelparambase.cpp create mode 100644 indra/newview/llscrollingpanelparambase.h diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index 96604270d..946073b97 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -29,6 +29,9 @@ * $/LicenseInfo$ */ +#ifndef LL_LLSCROLLINGPANELLIST_H +#define LL_LLSCROLLINGPANELLIST_H + #include #include "llui.h" @@ -56,6 +59,8 @@ public: LLScrollingPanelList(const std::string& name, const LLRect& rect) : LLUICtrl(name, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_BOTTOM ) {} + typedef std::deque panel_list_t; + virtual void setValue(const LLSD& value) {}; virtual void draw(); @@ -64,11 +69,16 @@ public: void addPanel( LLScrollingPanel* panel ); void updatePanels(BOOL allow_modify); + const panel_list_t& getPanelList() { return mPanelList; } + virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); private: void updatePanelVisiblilty(); - std::deque mPanelList; + + panel_list_t mPanelList; }; + +#endif //LL_LLSCROLLINGPANELLIST_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7b06d351d..4959adaa5 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -341,6 +341,7 @@ set(viewer_SOURCE_FILES llpanelavatar.cpp llpanelclassified.cpp llpanelcontents.cpp + llpaneleditwearable.cpp llpaneldebug.cpp llpaneldirbrowser.cpp llpaneldirclassified.cpp @@ -404,6 +405,8 @@ set(viewer_SOURCE_FILES llregionposition.cpp llremoteparcelrequest.cpp llsavedsettingsglue.cpp + llscrollingpanelparam.cpp + llscrollingpanelparambase.cpp llselectmgr.cpp llsky.cpp llspatialpartition.cpp @@ -833,6 +836,7 @@ set(viewer_HEADER_FILES llpanelavatar.h llpanelclassified.h llpanelcontents.h + llpaneleditwearable.h llpaneldebug.h llpaneldirbrowser.h llpaneldirclassified.h @@ -898,6 +902,8 @@ set(viewer_HEADER_FILES llremoteparcelrequest.h llresourcedata.h llsavedsettingsglue.h + llscrollingpanelparam.h + llscrollingpanelparambase.h llselectmgr.h llsky.h llspatialpartition.h diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 61d1671e9..03a789c45 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -49,7 +49,7 @@ #include "lltoolmgr.h" #include "llviewermenu.h" #include "llscrollcontainer.h" -#include "llscrollingpanellist.h" +#include "llscrollingpanelparam.h" #include "llsliderctrl.h" #include "lltabcontainervertical.h" #include "llviewerwindow.h" @@ -78,6 +78,7 @@ #include "llviewercontrol.h" #include "lluictrlfactory.h" #include "llnotificationsutil.h" +#include "llpaneleditwearable.h" #include "statemachine/aifilepicker.h" #include "hippogridmanager.h" @@ -89,8 +90,6 @@ using namespace LLVOAvatarDefines; // Globals LLFloaterCustomize* gFloaterCustomize = NULL; -const F32 PARAM_STEP_TIME_THRESHOLD = 0.25f; - ///////////////////////////////////////////////////////////////////// // LLFloaterCustomizeObserver @@ -108,62 +107,6 @@ protected: // Local Constants -class LLWearableSaveAsDialog : public LLModalDialog -{ -private: - std::string mItemName; - void (*mCommitCallback)(LLWearableSaveAsDialog*,void*); - void* mCallbackUserData; - -public: - LLWearableSaveAsDialog( const std::string& desc, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata ) - : LLModalDialog( LLStringUtil::null, 240, 100 ), - mCommitCallback( commit_cb ), - mCallbackUserData( userdata ) - { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml"); - - childSetAction("Save", LLWearableSaveAsDialog::onSave, this ); - childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this ); - - childSetTextArg("name ed", "[DESC]", desc); - } - - virtual void startModal() - { - LLModalDialog::startModal(); - LLLineEditor* edit = getChild("name ed"); - if (!edit) return; - edit->setFocus(TRUE); - edit->selectAll(); - } - - const std::string& getItemName() { return mItemName; } - - static void onSave( void* userdata ) - { - LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; - self->mItemName = self->childGetValue("name ed").asString(); - LLStringUtil::trim(self->mItemName); - if( !self->mItemName.empty() ) - { - if( self->mCommitCallback ) - { - self->mCommitCallback( self, self->mCallbackUserData ); - } - self->close(); // destroys this object - } - } - - static void onCancel( void* userdata ) - { - LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; - self->close(); // destroys this object - } -}; - -//////////////////////////////////////////////////////////////////////////// - BOOL edit_wearable_for_teens(LLWearableType::EType type) { switch(type) @@ -390,1331 +333,20 @@ public: } }; -///////////////////////////////////////////////////////////////////// -// LLPanelEditWearable - -enum ESubpart { - SUBPART_SHAPE_HEAD = 1, // avoid 0 - SUBPART_SHAPE_EYES, - SUBPART_SHAPE_EARS, - SUBPART_SHAPE_NOSE, - SUBPART_SHAPE_MOUTH, - SUBPART_SHAPE_CHIN, - SUBPART_SHAPE_TORSO, - SUBPART_SHAPE_LEGS, - SUBPART_SHAPE_WHOLE, - SUBPART_SHAPE_DETAIL, - SUBPART_SKIN_COLOR, - SUBPART_SKIN_FACEDETAIL, - SUBPART_SKIN_MAKEUP, - SUBPART_SKIN_BODYDETAIL, - SUBPART_HAIR_COLOR, - SUBPART_HAIR_STYLE, - SUBPART_HAIR_EYEBROWS, - SUBPART_HAIR_FACIAL, - SUBPART_EYES, - SUBPART_SHIRT, - SUBPART_PANTS, - SUBPART_SHOES, - SUBPART_SOCKS, - SUBPART_JACKET, - SUBPART_GLOVES, - SUBPART_UNDERSHIRT, - SUBPART_UNDERPANTS, - SUBPART_SKIRT, - SUBPART_ALPHA, - SUBPART_TATTOO, - SUBPART_PHYSICS_BREASTS_UPDOWN, - SUBPART_PHYSICS_BREASTS_INOUT, - SUBPART_PHYSICS_BREASTS_LEFTRIGHT, - SUBPART_PHYSICS_BELLY_UPDOWN, - SUBPART_PHYSICS_BUTT_UPDOWN, - SUBPART_PHYSICS_BUTT_LEFTRIGHT, - SUBPART_PHYSICS_ADVANCED - }; - -struct LLSubpart -{ - LLSubpart(const char* pJoint, const char* pGroup, const LLVector3d &target_offs, const LLVector3d &cam_offs, const ESex sex=SEX_BOTH, bool visual_hint=true ) - : mSex( sex ), mVisualHint(visual_hint), mTargetJoint(pJoint), mEditGroup(pGroup), mTargetOffset(target_offs), mCameraOffset(cam_offs) - {} - LLSubpart(const char* pJoint, const char* pGroup, const LLVector3d &target_offs, const LLVector3d &cam_offs, bool visual_hint) - : mSex( SEX_BOTH ), mVisualHint(visual_hint), mTargetJoint(pJoint), mEditGroup(pGroup), mTargetOffset(target_offs), mCameraOffset(cam_offs) - {} - std::string mButtonName; - std::string mTargetJoint; - std::string mEditGroup; - LLVector3d mTargetOffset; - LLVector3d mCameraOffset; - ESex mSex; - - bool mVisualHint; -}; - //////////////////////////////////////////////////////////////////////////// -class LLPanelEditWearable : public LLPanel -{ -public: - LLPanelEditWearable( LLWearableType::EType type ); - virtual ~LLPanelEditWearable(); - - virtual BOOL postBuild(); - virtual void draw(); - virtual BOOL isDirty() const; // LLUICtrl - - void addSubpart(const std::string& name, ESubpart id, LLSubpart* part ); - void addTextureDropTarget( ETextureIndex te, const std::string& name, const LLUUID& default_image_id, BOOL allow_no_texture ); - void addInvisibilityCheckbox(ETextureIndex te, const std::string& name); - void addColorSwatch( ETextureIndex te, const std::string& name ); - - const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); } - LLWearableType::EType getType() { return mType; } - - LLSubpart* getCurrentSubpart() { return mSubpartList[mCurrentSubpart]; } - ESubpart getDefaultSubpart(); - void setSubpart( ESubpart subpart ); - void switchToDefaultSubpart(); - - void setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete); - - void setUIPermissions(U32 perm_mask, BOOL is_complete); - - void hideTextureControls(); - bool textureIsInvisible(ETextureIndex te); - void initPreviousTextureList(); - void initPreviousTextureListEntry(ETextureIndex te); - - virtual void setVisible( BOOL visible ); - - // Callbacks - static void onBtnSubpart( void* userdata ); - static void onBtnTakeOff( void* userdata ); - static void onBtnSave( void* userdata ); - - static void onBtnSaveAs( void* userdata ); - static void onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ); - - static void onBtnRevert( void* userdata ); - static void onBtnTakeOffDialog( S32 option, void* userdata ); - static void onBtnCreateNew( void* userdata ); - static void onTextureCommit( LLUICtrl* ctrl, void* userdata ); - static void onInvisibilityCommit( LLUICtrl* ctrl, void* userdata ); - static void onColorCommit( LLUICtrl* ctrl, void* userdata ); - static void onCommitSexChange( LLUICtrl*, void* userdata ); - static bool onSelectAutoWearOption(const LLSD& notification, const LLSD& response); - - - -private: - LLWearableType::EType mType; - BOOL mCanTakeOff; - std::map mTextureList; - std::map mInvisibilityList; - std::map mColorList; - std::map mSubpartList; - std::map mPreviousTextureList; - ESubpart mCurrentSubpart; -}; - -//////////////////////////////////////////////////////////////////////////// - -LLPanelEditWearable::LLPanelEditWearable( LLWearableType::EType type ) - : LLPanel( LLWearableType::getTypeLabel( type ) ), - mType( type ) -{ -} - -BOOL LLPanelEditWearable::postBuild() -{ - LLAssetType::EType asset_type = LLWearableType::getAssetType( mType ); - /*std::string icon_name = (asset_type == LLAssetType::AT_CLOTHING ? - "inv_item_clothing.tga" : - "inv_item_skin.tga" );*/ - std::string icon_name = LLInventoryIcon::getIconName(asset_type,LLInventoryType::IT_WEARABLE,mType,FALSE); - - childSetValue("icon", icon_name); - - childSetAction("Create New", LLPanelEditWearable::onBtnCreateNew, this ); - - // If PG, can't take off underclothing or shirt - mCanTakeOff = - LLWearableType::getAssetType( mType ) == LLAssetType::AT_CLOTHING && - !( gAgent.isTeen() && (mType == LLWearableType::WT_UNDERSHIRT || mType == LLWearableType::WT_UNDERPANTS) ); - childSetVisible("Take Off", mCanTakeOff); - childSetAction("Take Off", LLPanelEditWearable::onBtnTakeOff, this ); - - childSetAction("Save", &LLPanelEditWearable::onBtnSave, (void*)this ); - - childSetAction("Save As", &LLPanelEditWearable::onBtnSaveAs, (void*)this ); - - childSetAction("Revert", &LLPanelEditWearable::onBtnRevert, (void*)this ); - - return TRUE; -} - -LLPanelEditWearable::~LLPanelEditWearable() -{ - std::for_each(mSubpartList.begin(), mSubpartList.end(), DeletePairedPointer()); - - // Clear colorswatch commit callbacks that point to this object. - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - childSetCommitCallback(iter->first, NULL, NULL); - } -} - -void LLPanelEditWearable::addSubpart( const std::string& name, ESubpart id, LLSubpart* part ) -{ - if (!name.empty()) - { - childSetAction(name, &LLPanelEditWearable::onBtnSubpart, (void*)id); - part->mButtonName = name; - } - mSubpartList[id] = part; - -} - -// static -void LLPanelEditWearable::onBtnSubpart(void* userdata) -{ - LLFloaterCustomize* floater_customize = gFloaterCustomize; - if (!floater_customize) return; - LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel(); - if (!self) return; - ESubpart subpart = (ESubpart) (intptr_t)userdata; - self->setSubpart( subpart ); -} - -void LLPanelEditWearable::setSubpart( ESubpart subpart ) -{ - mCurrentSubpart = subpart; - - for (std::map::iterator iter = mSubpartList.begin(); - iter != mSubpartList.end(); ++iter) - { - LLButton* btn = getChild(iter->second->mButtonName); - if (btn) - { - btn->setToggleState( subpart == iter->first ); - } - } - - LLSubpart* part = get_if_there(mSubpartList, (ESubpart)subpart, (LLSubpart*)NULL); - if( part ) - { - // Update the thumbnails we display - LLFloaterCustomize::param_map sorted_params; - LLVOAvatar* avatar = gAgentAvatarp; - ESex avatar_sex = avatar->getSex(); - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType,0); // TODO: MULTI-WEARABLE - U32 perm_mask = 0x0; - BOOL is_complete = FALSE; - bool can_export = false; - bool can_import = false; - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - - if (subpart <= 18) // body parts only - { - can_import = true; - - if (is_complete && - gAgent.getID() == item->getPermissions().getOwner() && - gAgent.getID() == item->getPermissions().getCreator() && - (PERM_ITEM_UNRESTRICTED & - perm_mask) == PERM_ITEM_UNRESTRICTED) - { - can_export = true; - } - } - } - setUIPermissions(perm_mask, is_complete); - BOOL editable = ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE; - - for(LLViewerVisualParam* param = (LLViewerVisualParam *)avatar->getFirstVisualParam(); - param; - param = (LLViewerVisualParam *)avatar->getNextVisualParam()) - { - if (param->getID() == -1 - || !param->isTweakable() - || param->getEditGroup() != part->mEditGroup - || !(param->getSex() & avatar_sex)) - { - continue; - } - - // negative getDisplayOrder() to make lowest order the highest priority - LLFloaterCustomize::param_map::value_type vt(-param->getDisplayOrder(), LLFloaterCustomize::editable_param(editable, param)); - llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates - sorted_params.insert(vt); - } - gFloaterCustomize->generateVisualParamHints(NULL, sorted_params, part->mVisualHint); - gFloaterCustomize->updateScrollingPanelUI(); - gFloaterCustomize->childSetEnabled("Export", can_export); - gFloaterCustomize->childSetEnabled("Import", can_import); - - // Update the camera - gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( part->mTargetJoint ) ); - gMorphView->setCameraTargetOffset( part->mTargetOffset ); - gMorphView->setCameraOffset( part->mCameraOffset ); - gMorphView->setCameraDistToDefault(); - if (gSavedSettings.getBOOL("AppearanceCameraMovement")) - { - gMorphView->updateCamera(); - } - } -} - -// static -void LLPanelEditWearable::onBtnTakeOff( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - - LLWearable* wearable = gAgentWearables.getWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE - if( !wearable ) - { - return; - } - - gAgentWearables.removeWearable( self->mType, false, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnSave( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.saveWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnSaveAs( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->getType(), 0 ); // TODO: MULTI-WEARABLE - if( wearable ) - { - LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self ); - save_as_dialog->startModal(); - // LLWearableSaveAsDialog deletes itself. - } -} - -// static -void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar ) - { - gAgentWearables.saveWearableAs( self->getType(), 0, save_as_dialog->getItemName(), FALSE ); // TODO: MULTI-WEARABLE - } -} - - -// static -void LLPanelEditWearable::onBtnRevert( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.revertWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnCreateNew( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLSD payload; - payload["wearable_type"] = (S32)self->getType(); - LLNotificationsUtil::add("AutoWearNewClothing", LLSD(), payload, &onSelectAutoWearOption); -} - -bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLVOAvatar* avatar = gAgentAvatarp; - if(avatar) - { - // Create a new wearable in the default folder for the wearable's asset type. - LLWearable* wearable = LLWearableList::instance().createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger() ); - LLAssetType::EType asset_type = wearable->getAssetType(); - - LLUUID folder_id; - // regular UI, items get created in normal folder - folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); - - // Only auto wear the new item if the AutoWearNewClothing checkbox is selected. - LLPointer cb = option == 0 ? - new WearOnAvatarCallback : NULL; - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), - asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), cb); - } - return false; -} - -bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) -{ - const LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if(wearable) - { - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - return (lto && lto->getID() == IMG_INVISIBLE); - } - return false; -} - -void LLPanelEditWearable::addInvisibilityCheckbox(ETextureIndex te, const std::string& name) -{ - childSetCommitCallback(name, LLPanelEditWearable::onInvisibilityCommit, this); - - mInvisibilityList[name] = te; -} - -// static -void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLCheckBoxCtrl* checkbox_ctrl = (LLCheckBoxCtrl*) ctrl; - if (!gAgentAvatarp) - { - return; - } - - ETextureIndex te = (ETextureIndex)(self->mInvisibilityList[ctrl->getName()]); - - bool new_invis_state = checkbox_ctrl->get(); - if (new_invis_state) - { - - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); - - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - const LLLocalTextureObject* lto = wearable ? wearable->getLocalTextureObject(te) : NULL; - - if(lto) - { - self->mPreviousTextureList[(S32)te] = lto->getID(); - } - if(wearable) - { - LLLocalTextureObject new_lto(image, IMG_INVISIBLE); - wearable->setLocalTextureObject(te, new_lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - - } - else - { - // Try to restore previous texture, if any. - LLUUID prev_id = self->mPreviousTextureList[(S32)te]; - if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) - { - prev_id = LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")); - } - if (prev_id.notNull()) - { - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - if(wearable) - { - LLLocalTextureObject new_lto(image, prev_id); - wearable->setLocalTextureObject(te, new_lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - } - - } -} - -void LLPanelEditWearable::addColorSwatch( ETextureIndex te, const std::string& name ) -{ - childSetCommitCallback(name, LLPanelEditWearable::onColorCommit, this); - mColorList[name] = te; -} - -// static -void LLPanelEditWearable::onColorCommit( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLColorSwatchCtrl* color_ctrl = (LLColorSwatchCtrl*) ctrl; - - if( self && color_ctrl && gAgentAvatarp ) - { - std::map::const_iterator cl_itr = self->mColorList.find(ctrl->getName()); - if(cl_itr != self->mColorList.end()) - { - ETextureIndex te = (ETextureIndex)cl_itr->second; - - LLWearable* wearable = gAgentWearables.getWearable(self->mType, 0); // TODO: MULTI-WEARABLE - if(!wearable) - return; - - LLColor4 old_color = wearable->getClothesColor( te ); - const LLColor4& new_color = color_ctrl->get(); - if( old_color != new_color ) - { - // Set the new version - wearable->setClothesColor(te, new_color, TRUE); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - LLVisualParamHint::requestHintUpdates(); - } - } - } -} - -void LLPanelEditWearable::initPreviousTextureList() -{ - initPreviousTextureListEntry(TEX_LOWER_ALPHA); - initPreviousTextureListEntry(TEX_UPPER_ALPHA); - initPreviousTextureListEntry(TEX_HEAD_ALPHA); - initPreviousTextureListEntry(TEX_EYES_ALPHA); - initPreviousTextureListEntry(TEX_LOWER_ALPHA); -} - -void LLPanelEditWearable::initPreviousTextureListEntry(ETextureIndex te) -{ - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if(!wearable) - return; - - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - if (lto) - { - mPreviousTextureList[te] = lto->getID(); - } -} - -void LLPanelEditWearable::addTextureDropTarget( ETextureIndex te, const std::string& name, - const LLUUID& default_image_id, BOOL allow_no_texture ) -{ - childSetCommitCallback(name, LLPanelEditWearable::onTextureCommit, this); - LLTextureCtrl* texture_ctrl = getChild(name); - if (texture_ctrl) - { - texture_ctrl->setDefaultImageAssetID(default_image_id); - texture_ctrl->setAllowNoTexture( allow_no_texture ); - // Don't allow (no copy) or (no transfer) textures to be selected. - texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); - texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); - } - mTextureList[name] = te; - LLVOAvatar* avatar = gAgentAvatarp; - if (avatar) - { - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if (wearable && mType == LLWearableType::WT_ALPHA) - { - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - if (lto) - { - mPreviousTextureList[te] = lto->getID(); - } - } - } -} - -// static -void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLTextureCtrl* texture_ctrl = (LLTextureCtrl*) ctrl; - - if( gAgentAvatarp ) - { - ETextureIndex te = (ETextureIndex)(self->mTextureList[ctrl->getName()]); - - // Set the new version - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( texture_ctrl->getImageAssetID() ); - if (image->getID().isNull()) - { - image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); - } - self->mTextureList[ctrl->getName()] = te; - - LLWearable* wearable = gAgentWearables.getWearable(self->mType, 0); // TODO: MULTI-WEARABLE - if (wearable) - { - LLLocalTextureObject lto(image, texture_ctrl->getImageAssetID()); - wearable->setLocalTextureObject(te, lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - if (self->mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) - { - self->mPreviousTextureList[te] = image->getID(); - } - } -} - - -ESubpart LLPanelEditWearable::getDefaultSubpart() -{ - switch( mType ) - { - case LLWearableType::WT_SHAPE: return SUBPART_SHAPE_WHOLE; - case LLWearableType::WT_SKIN: return SUBPART_SKIN_COLOR; - case LLWearableType::WT_HAIR: return SUBPART_HAIR_COLOR; - case LLWearableType::WT_EYES: return SUBPART_EYES; - case LLWearableType::WT_SHIRT: return SUBPART_SHIRT; - case LLWearableType::WT_PANTS: return SUBPART_PANTS; - case LLWearableType::WT_SHOES: return SUBPART_SHOES; - case LLWearableType::WT_SOCKS: return SUBPART_SOCKS; - case LLWearableType::WT_JACKET: return SUBPART_JACKET; - case LLWearableType::WT_GLOVES: return SUBPART_GLOVES; - case LLWearableType::WT_UNDERSHIRT: return SUBPART_UNDERSHIRT; - case LLWearableType::WT_UNDERPANTS: return SUBPART_UNDERPANTS; - case LLWearableType::WT_SKIRT: return SUBPART_SKIRT; - case LLWearableType::WT_ALPHA: return SUBPART_ALPHA; - case LLWearableType::WT_TATTOO: return SUBPART_TATTOO; - case LLWearableType::WT_PHYSICS: return SUBPART_PHYSICS_BELLY_UPDOWN; - - default: llassert(0); return SUBPART_SHAPE_WHOLE; - } -} - - -void LLPanelEditWearable::draw() -{ - if( gFloaterCustomize->isMinimized() ) - { - return; - } - - LLVOAvatar* avatar = gAgentAvatarp; - if( !avatar ) - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE - BOOL has_wearable = (wearable != NULL ); - BOOL is_dirty = isDirty(); - BOOL is_modifiable = FALSE; - BOOL is_copyable = FALSE; - BOOL is_complete = FALSE; - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType, 0); // TODO: MULTI-WEARABLE - if(item) - { - const LLPermissions& perm = item->getPermissions(); - is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); - is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()); - is_complete = item->isComplete(); - } - - childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty); - childSetEnabled("Save As", is_copyable && is_complete && has_wearable); - childSetEnabled("Revert", has_wearable && is_dirty ); - childSetEnabled("Take Off", has_wearable ); - childSetVisible("Take Off", mCanTakeOff && has_wearable ); - childSetVisible("Create New", !has_wearable ); - - childSetVisible("not worn instructions", !has_wearable ); - childSetVisible("no modify instructions", has_wearable && !is_modifiable); - - for (std::map::iterator iter = mSubpartList.begin(); - iter != mSubpartList.end(); ++iter) - { - childSetVisible(iter->second->mButtonName,has_wearable); - if( has_wearable && is_complete && is_modifiable ) - { - childSetEnabled(iter->second->mButtonName, iter->second->mSex & avatar->getSex() ); - } - else - { - childSetEnabled(iter->second->mButtonName, FALSE ); - } - } - - childSetVisible("square", !is_modifiable); - - childSetVisible("title", FALSE); - childSetVisible("title_no_modify", FALSE); - childSetVisible("title_not_worn", FALSE); - childSetVisible("title_loading", FALSE); - - childSetVisible("path", FALSE); - - LLTextBox *av_height = getChild("avheight",FALSE,FALSE); - if(av_height) //Only display this if the element exists - { - // Display the shape's nominal height. - // - // The value for avsize is the best available estimate from - // measuring against prims. - float avsize = avatar->mBodySize.mV[VZ] + .195; - int inches = (int)(avsize / .0254f); - int feet = inches / 12; - inches %= 12; - - std::ostringstream avheight(std::ostringstream::trunc); - avheight << std::fixed << std::setprecision(2) << avsize << " m (" - << feet << "' " << inches << "\")"; - av_height->setVisible(TRUE); - av_height->setTextArg("[AVHEIGHT]",avheight.str()); - } - - if(has_wearable && !is_modifiable) - { - // *TODO:Translate - childSetVisible("title_no_modify", TRUE); - childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - hideTextureControls(); - } - else if(has_wearable && !is_complete) - { - // *TODO:Translate - childSetVisible("title_loading", TRUE); - childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE - append_path(item_id, path); - childSetVisible("path", TRUE); - childSetTextArg("path", "[PATH]", path); - - hideTextureControls(); - } - else if(has_wearable && is_modifiable) - { - childSetVisible("title", TRUE); - childSetTextArg("title", "[DESC]", wearable->getName() ); - - std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE - append_path(item_id, path); - childSetVisible("path", TRUE); - childSetTextArg("path", "[PATH]", path); - - for( std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter ) - { - std::string name = iter->first; - LLTextureCtrl* texture_ctrl = getChild(name); - S32 te_index = iter->second; - childSetVisible(name, is_copyable && is_modifiable && is_complete ); - if (texture_ctrl) - { - - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te_index); - - LLUUID new_id; - - if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) - { - new_id = lto->getID(); - } - else - { - new_id = LLUUID::null; - } - - LLUUID old_id = texture_ctrl->getImageAssetID(); - - if (old_id != new_id) - { - // texture has changed, close the floater to avoid DEV-22461 - texture_ctrl->closeFloater(); - } - - texture_ctrl->setImageAssetID(new_id); - } - } - - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - - if(wearable) - { - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - std::string name = iter->first; - S32 te_index = iter->second; - childSetVisible(name, is_modifiable && is_complete ); - childSetEnabled(name, is_modifiable && is_complete ); - LLColorSwatchCtrl* ctrl = getChild(name); - if (ctrl) - { - ctrl->set( wearable->getClothesColor(te_index ) ); - } - } - } - - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - std::string name = iter->first; - ETextureIndex te = (ETextureIndex)iter->second; - childSetVisible(name, is_copyable && is_modifiable && is_complete); - childSetEnabled(name, is_copyable && is_modifiable && is_complete); - LLCheckBoxCtrl* ctrl = getChild(name); - if (ctrl) - { - ctrl->set(textureIsInvisible(te)); - } - } - } - else - { - // *TODO:Translate - childSetVisible("title_not_worn", TRUE); - childSetTextArg("title_not_worn", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - hideTextureControls(); - } - - childSetVisible("icon", has_wearable && is_modifiable); - - LLPanel::draw(); -} - -void LLPanelEditWearable::hideTextureControls() -{ - for (std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } - for (std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } -} - -void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete) -{ - if( wearable ) - { - setUIPermissions(perm_mask, is_complete); - if (mType == LLWearableType::WT_ALPHA) - { - initPreviousTextureList(); - } - } -} - -void LLPanelEditWearable::switchToDefaultSubpart() -{ - setSubpart( getDefaultSubpart() ); -} - -void LLPanelEditWearable::setVisible(BOOL visible) -{ - LLPanel::setVisible( visible ); - if( !visible ) - { - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - // this forces any open color pickers to cancel their selection - childSetEnabled(iter->first, FALSE ); - } - } -} - -BOOL LLPanelEditWearable::isDirty() const -{ - LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE - if( !wearable ) - { - return FALSE; - } - - if( wearable->isDirty() ) - { - return TRUE; - } - - return FALSE; -} - -// static -void LLPanelEditWearable::onCommitSexChange( LLUICtrl*, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) - { - return; - } - - if( !gAgentWearables.isWearableModifiable(self->mType, 0)) // TODO: MULTI-WEARABLE - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - if(!wearable) - { - return; - } - - ESex new_sex = gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE; - - LLVisualParam* param = avatar->getVisualParam( "male" ); - if( !param ) - { - return; - } - - wearable->setVisualParamWeight(param->getID(), (new_sex == SEX_MALE), TRUE); - wearable->writeToAvatar(); - avatar->updateVisualParams(); - - /*param->setWeight( (new_sex == SEX_MALE), TRUE ); - - avatar->updateSexDependentLayerSets( TRUE ); - - avatar->updateVisualParams();*/ - - gFloaterCustomize->clearScrollingPanelList(); - - // Assumes that we're in the "Shape" Panel. - self->setSubpart( SUBPART_SHAPE_WHOLE ); -} - -void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) -{ - BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE; - BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE; - - childSetEnabled("Save", is_modifiable && is_complete); - childSetEnabled("Save As", is_copyable && is_complete); - childSetEnabled("sex radio", is_modifiable && is_complete); - for( std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter ) - { - childSetVisible(iter->first, is_copyable && is_modifiable && is_complete ); - } - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - childSetVisible(iter->first, is_modifiable && is_complete ); - } - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - childSetVisible(iter->first, is_copyable && is_modifiable && is_complete); - } -} - -///////////////////////////////////////////////////////////////////// -// LLScrollingPanelParam - -class LLScrollingPanelParam : public LLScrollingPanel -{ -public: - LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ); - virtual ~LLScrollingPanelParam(); - - virtual void draw(); - virtual void setVisible( BOOL visible ); - virtual void updatePanel(BOOL allow_modify); - - static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata); - static void onSliderMoved(LLUICtrl* ctrl, void* userdata); - static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata); - - void onHintMouseUp( bool max ); - void onHintMouseDown( bool max ); - void onHintHeldDown( bool max ); - - F32 weightToPercent( F32 weight ); - F32 percentToWeight( F32 percent ); - -public: - LLViewerVisualParam* mParam; - LLPointer mHintMin; - LLPointer mHintMax; - LLButton* mLess; - LLButton* mMore; - - static S32 sUpdateDelayFrames; - -protected: - LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. - F32 mLastHeldTime; - - BOOL mAllowModify; -}; - -//static -S32 LLScrollingPanelParam::sUpdateDelayFrames = 0; - -const S32 BTN_BORDER = 2; -const S32 PARAM_HINT_WIDTH = 128; -const S32 PARAM_HINT_HEIGHT = 128; -const S32 PARAM_HINT_LABEL_HEIGHT = 16; -const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH); -const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; - -LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, - LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ) - : LLScrollingPanel( name, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 ) ), - mParam(param), - mAllowModify(allow_modify), - mLess(NULL), - mMore(NULL) -{ - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); - - //Set up the slider - LLSliderCtrl *slider = getChild("param slider"); - slider->setValue(weightToPercent(param->getWeight())); - slider->setLabelArg("[DESC]", param->getDisplayName()); - slider->setEnabled(mAllowModify); - slider->setCommitCallback(LLScrollingPanelParam::onSliderMoved); - slider->setCallbackUserData(this); - - if(bVisualHint) - { - S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; - S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT; - F32 min_weight = param->getMinWeight(); - F32 max_weight = param->getMaxWeight(); - - mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight); - pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; - mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight ); - - mHintMin->setAllowsUpdates( FALSE ); - mHintMax->setAllowsUpdates( FALSE ); - - // *TODO::translate - std::string min_name = param->getMinDisplayName(); - std::string max_name = param->getMaxDisplayName(); - childSetValue("min param text", min_name); - childSetValue("max param text", max_name); - mLess = getChild("less"); - mLess->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, false) ); - mLess->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, false) ); - mLess->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, false) ); - mLess->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); - - mMore = getChild("more"); - mMore->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, true) ); - mMore->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, true) ); - mMore->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, true) ); - mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); - } - else - { - //Kill everything that isn't the slider... - child_list_t to_remove; - child_list_t::const_iterator it; - for (it = getChildList()->begin(); it != getChildList()->end(); it++) - { - if ((*it) != slider && (*it)->getName() != "panel border") - { - to_remove.push_back(*it); - } - } - for (it = to_remove.begin(); it != to_remove.end(); it++) - { - removeChild(*it); - delete (*it); - } - slider->translate(0,PARAM_HINT_HEIGHT); - reshape(getRect().getWidth(),getRect().getHeight()-PARAM_HINT_HEIGHT); - } - - setVisible(FALSE); - setBorderVisible( FALSE ); -} - -LLScrollingPanelParam::~LLScrollingPanelParam() -{ - mHintMin = NULL; - mHintMax = NULL; -} - -void LLScrollingPanelParam::updatePanel(BOOL allow_modify) -{ - childSetValue("param slider", weightToPercent( mParam->getWeight() ) ); - if(mHintMin) - mHintMin->requestUpdate( sUpdateDelayFrames++ ); - if(mHintMax) - mHintMax->requestUpdate( sUpdateDelayFrames++ ); - - mAllowModify = allow_modify; - childSetEnabled("param slider", mAllowModify); - - if(mLess) - mLess->setEnabled(mAllowModify); - if(mMore) - mMore->setEnabled(mAllowModify); -} - -void LLScrollingPanelParam::setVisible( BOOL visible ) -{ - if( getVisible() != visible ) - { - LLPanel::setVisible( visible ); - if(mHintMin) - mHintMin->setAllowsUpdates( visible ); - if(mHintMax) - mHintMax->setAllowsUpdates( visible ); - - if( visible ) - { - if(mHintMin) - mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ ); - if(mHintMax) - mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ ); - } - } -} - -void LLScrollingPanelParam::draw() -{ - if( gFloaterCustomize->isMinimized() ) - { - return; - } - - if(mLess) - mLess->setVisible(mHintMin ? mHintMin->getVisible() : false); - if(mMore) - mMore->setVisible(mHintMax ? mHintMax->getVisible() : false); - - // Draw all the children except for the labels - childSetVisible( "min param text", FALSE ); - childSetVisible( "max param text", FALSE ); - LLPanel::draw(); - - // Draw the hints over the "less" and "more" buttons. - if(mHintMin) - { - gGL.pushMatrix(); - { - const LLRect& r = mHintMin->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - gGL.translatef(left, bot, 0.f); - mHintMin->draw(); - } - gGL.popMatrix(); - } - - if(mHintMax) - { - gGL.pushMatrix(); - { - const LLRect& r = mHintMax->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - gGL.translatef(left, bot, 0.f); - mHintMax->draw(); - } - gGL.popMatrix(); - } - - - // Draw labels on top of the buttons - childSetVisible( "min param text", TRUE ); - drawChild(getChild("min param text"), BTN_BORDER, BTN_BORDER); - - childSetVisible( "max param text", TRUE ); - drawChild(getChild("max param text"), BTN_BORDER, BTN_BORDER); -} - void updateAvatarHeightDisplay() { - if (gFloaterCustomize) - { - LLVOAvatar* avatar = gAgentAvatarp; - F32 avatar_size = (avatar->mBodySize.mV[VZ]) + (F32)0.17; //mBodySize is actually quite a bit off. - gFloaterCustomize->getChild("HeightTextM")->setValue(llformat("%.2f", avatar_size) + "m"); - F32 feet = avatar_size / 0.3048; - F32 inches = (feet - (F32)((U32)feet)) * 12.0; - gFloaterCustomize->getChild("HeightTextI")->setValue(llformat("%d'%d\"", (U32)feet, (U32)inches)); - } + if (gFloaterCustomize && isAgentAvatarValid()) + { + F32 avatar_size = (gAgentAvatarp->mBodySize.mV[VZ]) + (F32)0.17; //mBodySize is actually quite a bit off. + gFloaterCustomize->getChild("HeightTextM")->setValue(llformat("%.2f", avatar_size) + "m"); + F32 feet = avatar_size / 0.3048; + F32 inches = (feet - (F32)((U32)feet)) * 12.0; + gFloaterCustomize->getChild("HeightTextI")->setValue(llformat("%d'%d\"", (U32)feet, (U32)inches)); + } } -// static -void LLScrollingPanelParam::onSliderMoved(LLUICtrl* ctrl, void* userdata) -{ - LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; - LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; - LLViewerVisualParam* param = self->mParam; - - if(!param) - return; - - LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)param->getWearableType(), 0 ); // TODO: MULTI-WEARABLE - - if(!wearable) - return; - - F32 current_weight = wearable->getVisualParamWeight(param->getID()); - F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); - if (current_weight != new_weight ) - { - updateAvatarHeightDisplay(); - wearable->setVisualParamWeight( param->getID(), new_weight, FALSE); - wearable->writeToAvatar(); - gAgentAvatarp->updateVisualParams(); - } -} - -// static -void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata) -{ -} - -// static -void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata) -{ - LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; - - LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); -} - -void LLScrollingPanelParam::onHintMouseDown( bool max ) -{ - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - // morph towards this result - F32 current_weight = gAgentAvatarp->getVisualParamWeight( hint->getVisualParam() ); - - // if we have maxed out on this morph, we shouldn't be able to click it - if( hint->getVisualParamWeight() != current_weight ) - { - mMouseDownTimer.reset(); - mLastHeldTime = 0.f; - } -} - -void LLScrollingPanelParam::onHintHeldDown( bool max ) -{ - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - LLViewerVisualParam* param = hint->getVisualParam(); - - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE - - if(!wearable) - return; - - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); - - if (current_weight != hint->getVisualParamWeight() ) - { - const F32 FULL_BLEND_TIME = 2.f; - F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime; - mLastHeldTime += elapsed_time; - - F32 new_weight; - if (current_weight > hint->getVisualParamWeight() ) - { - new_weight = current_weight - (elapsed_time / FULL_BLEND_TIME); - } - else - { - new_weight = current_weight + (elapsed_time / FULL_BLEND_TIME); - } - - // Make sure we're not taking the slider out of bounds - // (this is where some simple UI limits are stored) - F32 new_percent = weightToPercent(new_weight); - LLSliderCtrl* slider = getChild("param slider"); - if (slider) - { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); - wearable->writeToAvatar(); - gAgentAvatarp->updateVisualParams(); - - slider->setValue( weightToPercent( new_weight ) ); - } - } - } -} - -void LLScrollingPanelParam::onHintMouseUp( bool max ) -{ - F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32(); - - LLVOAvatar* avatar = gAgentAvatarp; - if (avatar) - { - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - - if (elapsed_time < PARAM_STEP_TIME_THRESHOLD) - { - LLViewerVisualParam* param = hint->getVisualParam(); - - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); - if(wearable) - { - // step in direction - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); - F32 range = mHintMax->getVisualParamWeight() - mHintMin->getVisualParamWeight(); - //if min, range should be negative. - if(!max) - range *= -1.f; - // step a fraction in the negative direction - F32 new_weight = current_weight + (range / 10.f); - F32 new_percent = weightToPercent(new_weight); - LLSliderCtrl* slider = getChild("param slider"); - if (slider) - { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); - wearable->writeToAvatar(); - slider->setValue( weightToPercent( new_weight ) ); - } - } - } - } - } - - LLVisualParamHint::requestHintUpdates( mHintMin, mHintMax ); -} - - -F32 LLScrollingPanelParam::weightToPercent( F32 weight ) -{ - LLViewerVisualParam* param = mParam; - return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; -} - -F32 LLScrollingPanelParam::percentToWeight( F32 percent ) -{ - LLViewerVisualParam* param = mParam; - return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); -} - -const std::string& LLFloaterCustomize::getEditGroup() -{ - return getCurrentWearablePanel()->getCurrentSubpart()->mEditGroup; -} - - ///////////////////////////////////////////////////////////////////// // LLFloaterCustomize @@ -2055,325 +687,6 @@ void* LLFloaterCustomize::createWearablePanel(void* userdata) void LLFloaterCustomize::initWearablePanels() { - ///////////////////////////////////////// - // Shape - LLPanelEditWearable* panel = mWearablePanelList[ LLWearableType::WT_SHAPE ]; - - // body - LLSubpart* part = new LLSubpart("mPelvis", "shape_body", LLVector3d(0.f,0.f,0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart( "Body", SUBPART_SHAPE_WHOLE, part ); - - // head supparts - const LLVector3d head_target(0.f, 0.f, 0.05f); - const LLVector3d head_camera(-0.5f, 0.05f, 0.07f); - - part = new LLSubpart("mHead", "shape_head", head_target, head_camera); - panel->addSubpart( "Head", SUBPART_SHAPE_HEAD, part ); - - part = new LLSubpart("mHead", "shape_eyes", head_target, head_camera); - panel->addSubpart( "Eyes", SUBPART_SHAPE_EYES, part ); - - part = new LLSubpart("mHead", "shape_ears", head_target, head_camera); - panel->addSubpart( "Ears", SUBPART_SHAPE_EARS, part ); - - part = new LLSubpart("mHead", "shape_nose", head_target, head_camera); - panel->addSubpart( "Nose", SUBPART_SHAPE_NOSE, part ); - - part = new LLSubpart("mHead", "shape_mouth", head_target, head_camera); - panel->addSubpart( "Mouth", SUBPART_SHAPE_MOUTH, part ); - - part = new LLSubpart("mHead", "shape_chin", head_target, head_camera); - panel->addSubpart( "Chin", SUBPART_SHAPE_CHIN, part ); - - // torso - part = new LLSubpart("mTorso", "shape_torso", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( "Torso", SUBPART_SHAPE_TORSO, part ); - - // legs - part = new LLSubpart("mPelvis", "shape_legs", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( "Legs", SUBPART_SHAPE_LEGS, part ); - - panel->childSetCommitCallback("sex radio", LLPanelEditWearable::onCommitSexChange, panel); - - ///////////////////////////////////////// - // Skin - panel = mWearablePanelList[ LLWearableType::WT_SKIN ]; - - part = new LLSubpart("mHead", "skin_color", head_target, head_camera); - panel->addSubpart( "Skin Color", SUBPART_SKIN_COLOR, part ); - - part = new LLSubpart("mHead", "skin_facedetail", head_target, head_camera); - panel->addSubpart( "Face Detail", SUBPART_SKIN_FACEDETAIL, part ); - - part = new LLSubpart("mHead", "skin_makeup", head_target, head_camera); - panel->addSubpart( "Makeup", SUBPART_SKIN_MAKEUP, part ); - - part = new LLSubpart("mPelvis", "skin_bodydetail", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f)); - panel->addSubpart( "Body Detail", SUBPART_SKIN_BODYDETAIL, part ); - - panel->addTextureDropTarget( TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE ); - panel->addTextureDropTarget( TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE ); - panel->addTextureDropTarget( TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE ); - - ///////////////////////////////////////// - // Hair - panel = mWearablePanelList[ LLWearableType::WT_HAIR ]; - - part = new LLSubpart("mHead", "hair_color", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f)); - panel->addSubpart( "Color", SUBPART_HAIR_COLOR, part ); - - part = new LLSubpart("mHead", "hair_style", head_target, head_camera); - panel->addSubpart( "Style", SUBPART_HAIR_STYLE, part ); - - part = new LLSubpart("mHead", "hair_eyebrows", head_target, head_camera); - panel->addSubpart( "Eyebrows", SUBPART_HAIR_EYEBROWS, part ); - - part = new LLSubpart("mHead", "hair_facial", head_target, head_camera, SEX_MALE); - panel->addSubpart( "Facial", SUBPART_HAIR_FACIAL, part ); - - panel->addTextureDropTarget(TEX_HAIR, "Texture", - LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), - FALSE ); - - ///////////////////////////////////////// - // Eyes - panel = mWearablePanelList[ LLWearableType::WT_EYES ]; - - part = new LLSubpart("mHead", "eyes", head_target, head_camera); - panel->addSubpart( LLStringUtil::null, SUBPART_EYES, part ); - - panel->addTextureDropTarget(TEX_EYES_IRIS, "Iris", - LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), - FALSE ); - - ///////////////////////////////////////// - // Shirt - panel = mWearablePanelList[ LLWearableType::WT_SHIRT ]; - - part = new LLSubpart("mTorso", "shirt", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SHIRT, part ); - - panel->addTextureDropTarget( TEX_UPPER_SHIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_SHIRT, "Color/Tint" ); - - - ///////////////////////////////////////// - // Pants - panel = mWearablePanelList[ LLWearableType::WT_PANTS ]; - - part = new LLSubpart("mPelvis", "pants", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_PANTS, part ); - - panel->addTextureDropTarget(TEX_LOWER_PANTS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_PANTS, "Color/Tint" ); - - - ///////////////////////////////////////// - // Shoes - panel = mWearablePanelList[ LLWearableType::WT_SHOES ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "shoes", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SHOES, part ); - - panel->addTextureDropTarget( TEX_LOWER_SHOES, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_SHOES, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Socks - panel = mWearablePanelList[ LLWearableType::WT_SOCKS ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "socks", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SOCKS, part ); - - panel->addTextureDropTarget( TEX_LOWER_SOCKS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_SOCKS, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Jacket - panel = mWearablePanelList[ LLWearableType::WT_JACKET ]; - - if (panel) - { - part = new LLSubpart("mTorso", "jacket", LLVector3d(), LLVector3d(-2.f, 0.1f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_JACKET, part ); - - panel->addTextureDropTarget( TEX_UPPER_JACKET, "Upper Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), - FALSE ); - panel->addTextureDropTarget( TEX_LOWER_JACKET, "Lower Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_JACKET, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Skirt - panel = mWearablePanelList[ LLWearableType::WT_SKIRT ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "skirt", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SKIRT, part ); - - panel->addTextureDropTarget( TEX_SKIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_SKIRT, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Gloves - panel = mWearablePanelList[ LLWearableType::WT_GLOVES ]; - - if (panel) - { - part = new LLSubpart("mTorso", "gloves", LLVector3d(), LLVector3d(-1.f, 0.15f, 0.f)); - panel->addSubpart( LLStringUtil::null, SUBPART_GLOVES, part ); - - panel->addTextureDropTarget( TEX_UPPER_GLOVES, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_GLOVES, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Undershirt - panel = mWearablePanelList[ LLWearableType::WT_UNDERSHIRT ]; - - if (panel) - { - part = new LLSubpart("mTorso", "undershirt", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_UNDERSHIRT, part ); - - panel->addTextureDropTarget( TEX_UPPER_UNDERSHIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_UNDERSHIRT, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Underpants - panel = mWearablePanelList[ LLWearableType::WT_UNDERPANTS ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "underpants", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_UNDERPANTS, part ); - - panel->addTextureDropTarget( TEX_LOWER_UNDERPANTS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_UNDERPANTS, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Alpha - panel = mWearablePanelList[LLWearableType::WT_ALPHA]; - - if (panel) - { - part = new LLSubpart("mPelvis", "alpha", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart(LLStringUtil::null, SUBPART_ALPHA, part); - - panel->addTextureDropTarget(TEX_LOWER_ALPHA, "Lower Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_UPPER_ALPHA, "Upper Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_HEAD_ALPHA, "Head Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_EYES_ALPHA, "Eye Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_HAIR_ALPHA, "Hair Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - - panel->addInvisibilityCheckbox(TEX_LOWER_ALPHA, "lower alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_UPPER_ALPHA, "upper alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_HEAD_ALPHA, "head alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_EYES_ALPHA, "eye alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_HAIR_ALPHA, "hair alpha texture invisible"); - } - - ///////////////////////////////////////// - // Tattoo - panel = mWearablePanelList[LLWearableType::WT_TATTOO]; - - if (panel) - { - part = new LLSubpart("mPelvis", "tattoo", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart(LLStringUtil::null, SUBPART_TATTOO, part); - - panel->addTextureDropTarget(TEX_LOWER_TATTOO, "Lower Tattoo", - LLUUID::null, - TRUE); - panel->addTextureDropTarget(TEX_UPPER_TATTOO, "Upper Tattoo", - LLUUID::null, - TRUE); - panel->addTextureDropTarget(TEX_HEAD_TATTOO, "Head Tattoo", - LLUUID::null, - TRUE); - panel->addColorSwatch(TEX_LOWER_TATTOO, "Color/Tint"); //-ASC-TTRFE - } - - ///////////////////////////////////////// - // Physics - - panel = mWearablePanelList[LLWearableType::WT_PHYSICS]; - - if(panel) - { - part = new LLSubpart("mTorso", "physics_breasts_updown", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Bounce", SUBPART_PHYSICS_BREASTS_UPDOWN, part); - - part = new LLSubpart("mTorso", "physics_breasts_inout", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Cleavage", SUBPART_PHYSICS_BREASTS_INOUT, part); - - part = new LLSubpart("mTorso", "physics_breasts_leftright", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Sway", SUBPART_PHYSICS_BREASTS_LEFTRIGHT, part); - - part = new LLSubpart("mTorso", "physics_belly_updown", LLVector3d(0.f, 0.f, -.05f), LLVector3d(-0.8f, 0.15f, 0.38f), false); - panel->addSubpart("Belly Bounce", SUBPART_PHYSICS_BELLY_UPDOWN, part); - - part = new LLSubpart("mPelvis", "physics_butt_updown", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f), false); - panel->addSubpart("Butt Bounce", SUBPART_PHYSICS_BUTT_UPDOWN, part); - - part = new LLSubpart("mPelvis", "physics_butt_leftright", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f), false); - panel->addSubpart("Butt Sway", SUBPART_PHYSICS_BUTT_LEFTRIGHT, part); - - part = new LLSubpart("mTorso", "physics_advanced", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), false); - panel->addSubpart("Advanced Parameters", SUBPART_PHYSICS_ADVANCED, part); - - } } //////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index c19a570ad..d4e7e1ad5 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -91,7 +91,6 @@ public: void generateVisualParamHints(LLViewerJointMesh* joint_mesh, param_map& params, bool bVisualHint); - const std::string& getEditGroup(); void updateScrollingPanelList(BOOL allow_modify); void setWearable(LLWearableType::EType type, LLWearable* wearable, U32 perm_mask, BOOL is_complete); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp new file mode 100644 index 000000000..80780594d --- /dev/null +++ b/indra/newview/llpaneleditwearable.cpp @@ -0,0 +1,1405 @@ +/** + * @file llpaneleditwearable.cpp + * @brief UI panel for editing of a particular wearable item. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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" + +#include "llpaneleditwearable.h" +#include "llpanel.h" +#include "llwearable.h" +#include "lluictrl.h" +#include "llscrollingpanellist.h" +#include "llvisualparam.h" +#include "lltoolmorph.h" +#include "llviewerjointmesh.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llvoavatarself.h" +#include "lltexteditor.h" +#include "lltextbox.h" +#include "llagentwearables.h" +#include "llscrollingpanelparam.h" +#include "llradiogroup.h" +#include "llnotificationsutil.h" + +#include "llcolorswatch.h" +#include "lltexturectrl.h" +#include "lltextureentry.h" +#include "llviewercontrol.h" // gSavedSettings +#include "llviewertexturelist.h" +#include "llagentcamera.h" +#include "llmorphview.h" + +#include "llcommandhandler.h" +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "llfloatercustomize.h" + +#include "llwearablelist.h" + +// subparts of the UI for focus, camera position, etc. +enum ESubpart { + SUBPART_SHAPE_HEAD = 1, // avoid 0 + SUBPART_SHAPE_EYES, + SUBPART_SHAPE_EARS, + SUBPART_SHAPE_NOSE, + SUBPART_SHAPE_MOUTH, + SUBPART_SHAPE_CHIN, + SUBPART_SHAPE_TORSO, + SUBPART_SHAPE_LEGS, + SUBPART_SHAPE_WHOLE, + SUBPART_SHAPE_DETAIL, + SUBPART_SKIN_COLOR, + SUBPART_SKIN_FACEDETAIL, + SUBPART_SKIN_MAKEUP, + SUBPART_SKIN_BODYDETAIL, + SUBPART_HAIR_COLOR, + SUBPART_HAIR_STYLE, + SUBPART_HAIR_EYEBROWS, + SUBPART_HAIR_FACIAL, + SUBPART_EYES, + SUBPART_SHIRT, + SUBPART_PANTS, + SUBPART_SHOES, + SUBPART_SOCKS, + SUBPART_JACKET, + SUBPART_GLOVES, + SUBPART_UNDERSHIRT, + SUBPART_UNDERPANTS, + SUBPART_SKIRT, + SUBPART_ALPHA, + SUBPART_TATTOO, + SUBPART_PHYSICS_BREASTS_UPDOWN, + SUBPART_PHYSICS_BREASTS_INOUT, + SUBPART_PHYSICS_BREASTS_LEFTRIGHT, + SUBPART_PHYSICS_BELLY_UPDOWN, + SUBPART_PHYSICS_BUTT_UPDOWN, + SUBPART_PHYSICS_BUTT_LEFTRIGHT, + SUBPART_PHYSICS_ADVANCED, + }; + +using namespace LLVOAvatarDefines; + +typedef std::vector subpart_vec_t; + +// Locally defined classes + +class LLEditWearableDictionary : public LLSingleton +{ + //-------------------------------------------------------------------- + // Constructors and Destructors + //-------------------------------------------------------------------- +public: + LLEditWearableDictionary(); + virtual ~LLEditWearableDictionary(); + + //-------------------------------------------------------------------- + // Wearable Types + //-------------------------------------------------------------------- +public: + struct WearableEntry : public LLDictionaryEntry + { + WearableEntry(LLWearableType::EType type, + const std::string &title, + U8 num_color_swatches, // number of 'color_swatches' + U8 num_texture_pickers, // number of 'texture_pickers' + U8 num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts + + + const LLWearableType::EType mWearableType; + subpart_vec_t mSubparts; + texture_vec_t mColorSwatchCtrls; + texture_vec_t mTextureCtrls; + }; + + struct Wearables : public LLDictionary + { + Wearables(); + } mWearables; + + const WearableEntry* getWearable(LLWearableType::EType type) const { return mWearables.lookup(type); } + + //-------------------------------------------------------------------- + // Subparts + //-------------------------------------------------------------------- +public: + struct SubpartEntry : public LLDictionaryEntry + { + SubpartEntry(ESubpart part, + const std::string &joint, + const std::string &edit_group, + const std::string &button_name, + const LLVector3d &target_offset, + const LLVector3d &camera_offset, + const ESex &sex); + + + ESubpart mSubpart; + std::string mTargetJoint; + std::string mEditGroup; + std::string mButtonName; + LLVector3d mTargetOffset; + LLVector3d mCameraOffset; + ESex mSex; + }; + + struct Subparts : public LLDictionary + { + Subparts(); + } mSubparts; + + const SubpartEntry* getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); } + + //-------------------------------------------------------------------- + // Picker Control Entries + //-------------------------------------------------------------------- +public: + struct PickerControlEntry : public LLDictionaryEntry + { + PickerControlEntry(ETextureIndex tex_index, + const std::string name, + const LLUUID default_image_id = LLUUID::null, + const bool allow_no_texture = false, + const std::string checkbox_name = LLStringUtil::null); + ETextureIndex mTextureIndex; + const std::string mControlName; + const LLUUID mDefaultImageId; + const bool mAllowNoTexture; + std::string mCheckboxName; + }; + + struct ColorSwatchCtrls : public LLDictionary + { + ColorSwatchCtrls(); + } mColorSwatchCtrls; + + struct TextureCtrls : public LLDictionary + { + TextureCtrls(); + } mTextureCtrls; + + const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); } + const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); } +}; + +LLEditWearableDictionary::LLEditWearableDictionary() +{ + +} + +//virtual +LLEditWearableDictionary::~LLEditWearableDictionary() +{ +} + +LLEditWearableDictionary::Wearables::Wearables() +{ + // note the subpart that is listed first is treated as "default", regardless of what order is in enum. + // Please match the order presented in XUI. -Nyx + // this will affect what camera angle is shown when first editing a wearable + addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL)); + addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title",0,1,1, TEX_EYES_IRIS, SUBPART_EYES)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO)); + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS,"edit_physics_title",0,0,7, SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, SUBPART_PHYSICS_BELLY_UPDOWN, SUBPART_PHYSICS_BUTT_UPDOWN, SUBPART_PHYSICS_BUTT_LEFTRIGHT, SUBPART_PHYSICS_ADVANCED)); +} + +LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type, + const std::string &title, + U8 num_color_swatches, + U8 num_texture_pickers, + U8 num_subparts, ... ) : + LLDictionaryEntry(title), + mWearableType(type) +{ + va_list argp; + va_start(argp, num_subparts); + + for (U8 i = 0; i < num_color_swatches; ++i) + { + ETextureIndex index = (ETextureIndex)va_arg(argp,int); + mColorSwatchCtrls.push_back(index); + } + + for (U8 i = 0; i < num_texture_pickers; ++i) + { + ETextureIndex index = (ETextureIndex)va_arg(argp,int); + mTextureCtrls.push_back(index); + } + + for (U8 i = 0; i < num_subparts; ++i) + { + ESubpart part = (ESubpart)va_arg(argp,int); + mSubparts.push_back(part); + } +} + +LLEditWearableDictionary::Subparts::Subparts() +{ + addEntry(SUBPART_SHAPE_WHOLE, new SubpartEntry(SUBPART_SHAPE_WHOLE, "mPelvis", "shape_body","Body", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + const LLVector3d head_target(0.f, 0.f, 0.05f); + const LLVector3d head_camera(-0.5f, 0.05f, 0.07f); + addEntry(SUBPART_SHAPE_HEAD, new SubpartEntry(SUBPART_SHAPE_HEAD, "mHead", "shape_head","Head", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_EYES, new SubpartEntry(SUBPART_SHAPE_EYES, "mHead", "shape_eyes","Eyes", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_EARS, new SubpartEntry(SUBPART_SHAPE_EARS, "mHead", "shape_ears","Ears", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_NOSE, new SubpartEntry(SUBPART_SHAPE_NOSE, "mHead", "shape_nose","Nose", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_MOUTH, new SubpartEntry(SUBPART_SHAPE_MOUTH, "mHead", "shape_mouth","Mouth", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_CHIN, new SubpartEntry(SUBPART_SHAPE_CHIN, "mHead", "shape_chin","Chin", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_TORSO, new SubpartEntry(SUBPART_SHAPE_TORSO, "mTorso", "shape_torso","Torso", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_SHAPE_LEGS, new SubpartEntry(SUBPART_SHAPE_LEGS, "mPelvis", "shape_legs","Legs", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + + addEntry(SUBPART_SKIN_COLOR, new SubpartEntry(SUBPART_SKIN_COLOR, "mHead", "skin_color","Skin Color", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_FACEDETAIL, new SubpartEntry(SUBPART_SKIN_FACEDETAIL, "mHead", "skin_facedetail","Face Detail", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_MAKEUP, new SubpartEntry(SUBPART_SKIN_MAKEUP, "mHead", "skin_makeup","Makeup", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_BODYDETAIL, new SubpartEntry(SUBPART_SKIN_BODYDETAIL, "mPelvis", "skin_bodydetail","Body Detail", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f), SEX_BOTH)); + + addEntry(SUBPART_HAIR_COLOR, new SubpartEntry(SUBPART_HAIR_COLOR, "mHead", "hair_color","Color", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); + addEntry(SUBPART_HAIR_STYLE, new SubpartEntry(SUBPART_HAIR_STYLE, "mHead", "hair_style","Style", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); + addEntry(SUBPART_HAIR_EYEBROWS, new SubpartEntry(SUBPART_HAIR_EYEBROWS, "mHead", "hair_eyebrows","Eyebrows", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_HAIR_FACIAL, new SubpartEntry(SUBPART_HAIR_FACIAL, "mHead", "hair_facial","Facial", head_target, head_camera,SEX_MALE)); + + addEntry(SUBPART_EYES, new SubpartEntry(SUBPART_EYES, "mHead", "eyes",LLStringUtil::null, head_target, head_camera,SEX_BOTH)); + + addEntry(SUBPART_SHIRT, new SubpartEntry(SUBPART_SHIRT, "mTorso", "shirt",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_PANTS, new SubpartEntry(SUBPART_PANTS, "mPelvis", "pants",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_SHOES, new SubpartEntry(SUBPART_SHOES, "mPelvis", "shoes",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_SOCKS, new SubpartEntry(SUBPART_SOCKS, "mPelvis", "socks",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_JACKET, new SubpartEntry(SUBPART_JACKET, "mTorso", "jacket",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.f), LLVector3d(-2.f, 0.1f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_SKIRT, new SubpartEntry(SUBPART_SKIRT, "mPelvis", "skirt",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_GLOVES, new SubpartEntry(SUBPART_GLOVES, "mTorso", "gloves",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.f), LLVector3d(-1.f, 0.15f, 0.f), SEX_BOTH)); + addEntry(SUBPART_UNDERSHIRT, new SubpartEntry(SUBPART_UNDERSHIRT, "mTorso", "undershirt",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), SEX_BOTH)); + addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", LLStringUtil::null, LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, "mTorso", "physics_breasts_updown", "Breast Bounce", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BREASTS_INOUT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_INOUT, "mTorso", "physics_breasts_inout", "Breast Cleavage", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, "mTorso", "physics_breasts_leftright", "Breast Sway", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "Belly Bounce", LLVector3d(0.f, 0.f, -.05f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "Butt Bounce", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, "mTorso", "physics_butt_leftright", "Butt Sway", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_ADVANCED, new SubpartEntry(SUBPART_PHYSICS_ADVANCED, "mTorso", "physics_advanced", "Advanced Parameters", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); +} + +LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part, + const std::string &joint, + const std::string &edit_group, + const std::string &button_name, + const LLVector3d &target_offset, + const LLVector3d &camera_offset, + const ESex &sex) : + LLDictionaryEntry(edit_group), + mSubpart(part), + mTargetJoint(joint), + mEditGroup(edit_group), + mButtonName(button_name), + mTargetOffset(target_offset), + mCameraOffset(camera_offset), + mSex(sex) +{ +} + +LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls() +{ + addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" )); + addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" )); + addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" )); + addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" )); + addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" )); + addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" )); + addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" )); + addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" )); + addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" )); + addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" )); +} + +LLEditWearableDictionary::TextureCtrls::TextureCtrls() +{ + addEntry ( TEX_HEAD_BODYPAINT, new PickerControlEntry (TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE )); + addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); + addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "lower alpha texture invisible" )); + addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "upper alpha texture invisible" )); + addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "head alpha texture invisible" )); + addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "eye alpha texture invisible" )); + addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "hair alpha texture invisible" )); + addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE )); +} + +LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex tex_index, + const std::string name, + const LLUUID default_image_id, + const bool allow_no_texture, + const std::string checkbox_name) : + LLDictionaryEntry(name), + mTextureIndex(tex_index), + mControlName(name), + mDefaultImageId(default_image_id), + mAllowNoTexture(allow_no_texture), + mCheckboxName(checkbox_name) +{ +} + +// Helper functions. +static const texture_vec_t null_texture_vec; + +// Specializations of this template function return a vector of texture indexes of particular control type +// (i.e. LLColorSwatchCtrl or LLTextureCtrl) which are contained in given WearableEntry. +template +const texture_vec_t& +get_pickers_indexes(const LLEditWearableDictionary::WearableEntry *wearable_entry) { return null_texture_vec; } + +// Specializations of this template function return picker control entry for particular control type. +template +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) { return NULL; } + +typedef boost::function function_t; + +typedef struct PickerControlEntryNamePredicate +{ + PickerControlEntryNamePredicate(const std::string name) : mName (name) {}; + bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const + { + return (entry && entry->mName == mName); + } +private: + const std::string mName; +} PickerControlEntryNamePredicate; + +// A full specialization of get_pickers_indexes for LLColorSwatchCtrl +template <> +const texture_vec_t& +get_pickers_indexes (const LLEditWearableDictionary::WearableEntry *wearable_entry) +{ + if (!wearable_entry) + { + llwarns << "could not get LLColorSwatchCtrl indexes for null wearable entry." << llendl; + return null_texture_vec; + } + return wearable_entry->mColorSwatchCtrls; +} + +// A full specialization of get_pickers_indexes for LLTextureCtrl +template <> +const texture_vec_t& +get_pickers_indexes (const LLEditWearableDictionary::WearableEntry *wearable_entry) +{ + if (!wearable_entry) + { + llwarns << "could not get LLTextureCtrl indexes for null wearable entry." << llendl; + return null_texture_vec; + } + return wearable_entry->mTextureCtrls; +} + +// A full specialization of get_picker_entry for LLColorSwatchCtrl +template <> +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) +{ + return LLEditWearableDictionary::getInstance()->getColorSwatch(index); +} + +// A full specialization of get_picker_entry for LLTextureCtrl +template <> +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) +{ + return LLEditWearableDictionary::getInstance()->getTexturePicker(index); +} + +template +const LLEditWearableDictionary::PickerControlEntry* +find_picker_ctrl_entry_if(LLWearableType::EType type, const Predicate pred) +{ + const LLEditWearableDictionary::WearableEntry *wearable_entry + = LLEditWearableDictionary::getInstance()->getWearable(type); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl; + return NULL; + } + const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); + for (texture_vec_t::const_iterator + iter = indexes.begin(), + iter_end = indexes.end(); + iter != iter_end; ++iter) + { + const ETextureIndex te = *iter; + const LLEditWearableDictionary::PickerControlEntry* entry + = get_picker_entry(te); + if (!entry) + { + llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl; + continue; + } + if (pred(entry)) + { + return entry; + } + } + return NULL; +} + +template +void +for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun) +{ + if (!panel) + { + llwarns << "the panel wasn't passed for wearable of type: " << type << llendl; + return; + } + const LLEditWearableDictionary::WearableEntry *wearable_entry + = LLEditWearableDictionary::getInstance()->getWearable(type); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl; + return; + } + const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); + for (texture_vec_t::const_iterator + iter = indexes.begin(), + iter_end = indexes.end(); + iter != iter_end; ++iter) + { + const ETextureIndex te = *iter; + const LLEditWearableDictionary::PickerControlEntry* entry + = get_picker_entry(te); + if (!entry) + { + llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl; + continue; + } + fun (panel, entry); + } +} + +// The helper functions for pickers management +static void init_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onColorSwatchCommit, self, _1)); + // Can't get the color from the wearable here, since the wearable may not be set when this is called. + color_swatch_ctrl->setOriginal(LLColor4::white); + } +} + +static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + texture_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onTexturePickerCommit, self, _1)); + texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId); + texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture); + // Don't allow (no copy) or (notransfer) textures to be selected. + texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); + texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); + } + if(!entry->mCheckboxName.empty()) + { + LLCheckBoxCtrl* checkbox_ctrl = panel->getChild(entry->mCheckboxName, true, false); + if(checkbox_ctrl) + { + checkbox_ctrl->setCommitCallback(LLPanelEditWearable::onInvisibilityCommit, self); + self->initPreviousTextureListEntry(entry->mTextureIndex); + } + } +} + +static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex)); + } +} + +static void update_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + LLUUID new_id; + LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex); + if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) + { + new_id = lto->getID(); + } + else + { + new_id = LLUUID::null; + } + LLUUID old_id = texture_ctrl->getImageAssetID(); + if (old_id != new_id) + { + // texture has changed, close the floater to avoid DEV-22461 + texture_ctrl->closeFloater(); + } + texture_ctrl->setImageAssetID(new_id); + } +} + +static void set_enabled_color_swatch_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->setEnabled(enabled); + color_swatch_ctrl->setVisible(enabled); + } +} + +static void set_enabled_texture_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + texture_ctrl->setEnabled(enabled); + texture_ctrl->setVisible(enabled); + } +} + +static void set_enabled_invisibility_ctrl(bool enabled, LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + if(!entry->mCheckboxName.empty()) + { + LLCheckBoxCtrl* checkbox_ctrl = panel->getChild(entry->mCheckboxName, true, false); + if(checkbox_ctrl) + { + checkbox_ctrl->setEnabled(enabled); + checkbox_ctrl->setVisible(enabled); + checkbox_ctrl->set(!gAgentAvatarp->isTextureVisible(entry->mTextureIndex, self->getWearable())); + } + } +} + +class LLWearableSaveAsDialog : public LLModalDialog +{ +private: + std::string mItemName; + void (*mCommitCallback)(LLWearableSaveAsDialog*,void*); + void* mCallbackUserData; + +public: + LLWearableSaveAsDialog( const std::string& desc, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata ) + : LLModalDialog( LLStringUtil::null, 240, 100 ), + mCommitCallback( commit_cb ), + mCallbackUserData( userdata ) + { + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml"); + + childSetAction("Save", LLWearableSaveAsDialog::onSave, this ); + childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this ); + + childSetTextArg("name ed", "[DESC]", desc); + } + + virtual void startModal() + { + LLModalDialog::startModal(); + LLLineEditor* edit = getChild("name ed"); + if (!edit) return; + edit->setFocus(TRUE); + edit->selectAll(); + } + + const std::string& getItemName() { return mItemName; } + + static void onSave( void* userdata ) + { + LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; + self->mItemName = self->childGetValue("name ed").asString(); + LLStringUtil::trim(self->mItemName); + if( !self->mItemName.empty() ) + { + if( self->mCommitCallback ) + { + self->mCommitCallback( self, self->mCallbackUserData ); + } + self->close(); // destroys this object + } + } + + static void onCancel( void* userdata ) + { + LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; + self->close(); // destroys this object + } +}; + +LLPanelEditWearable::LLPanelEditWearable( LLWearableType::EType type ) + + : LLPanel( LLWearableType::getTypeLabel( type ) ), + mType( type ) +{ +} +LLPanelEditWearable::~LLPanelEditWearable() +{ +} + +BOOL LLPanelEditWearable::postBuild() +{ + std::string icon_name = LLInventoryIcon::getIconName(LLWearableType::getAssetType( mType ),LLInventoryType::IT_WEARABLE,mType,FALSE); + + childSetValue("icon", icon_name); + + childSetAction("Create New", LLPanelEditWearable::onBtnCreateNew, this ); + + // If PG, can't take off underclothing or shirt + mCanTakeOff = + LLWearableType::getAssetType( mType ) == LLAssetType::AT_CLOTHING && + !( gAgent.isTeen() && (mType == LLWearableType::WT_UNDERSHIRT || mType == LLWearableType::WT_UNDERPANTS) ); + childSetVisible("Take Off", mCanTakeOff); + childSetAction("Take Off", LLPanelEditWearable::onBtnTakeOff, this ); + + LLUICtrl* sex_radio = getChild("sex radio", true, false); + if(sex_radio) + { + sex_radio->setCommitCallback(boost::bind(&LLPanelEditWearable::onCommitSexChange,this)); + } + + childSetAction("Save", &LLPanelEditWearable::onBtnSave, (void*)this ); + + childSetAction("Save As", &LLPanelEditWearable::onBtnSaveAs, (void*)this ); + + childSetAction("Revert", &LLPanelEditWearable::onRevertButtonClicked, (void*)this ); + + { + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << mType << llendl; + } + U8 num_subparts = wearable_entry->mSubparts.size(); + + for (U8 index = 0; index < num_subparts; ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (!subpart_entry) + { + llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + continue; + } + + if(!subpart_entry->mButtonName.empty()) + { + llinfos << "Finding button " << subpart_entry->mButtonName << llendl; + llassert_always(getChild(subpart_entry->mButtonName,true,false)); + childSetAction(subpart_entry->mButtonName, &LLPanelEditWearable::onBtnSubpart, (void*)subpart_e); + } + } + // initialize texture and color picker controls + for_each_picker_ctrl_entry (this, mType, boost::bind(init_color_swatch_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(init_texture_ctrl, this, _1, _2)); + } + return TRUE; +} + +BOOL LLPanelEditWearable::isDirty() const +{ + LLWearable* wearable = getWearable(); + return wearable && wearable->isDirty(); +} + +void LLPanelEditWearable::draw() +{ + if( gFloaterCustomize->isMinimized() ) + { + return; + } + + LLVOAvatar* avatar = gAgentAvatarp; + if( !avatar ) + { + return; + } + + LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE + BOOL has_wearable = (wearable != NULL ); + BOOL is_dirty = isDirty(); + BOOL is_modifiable = FALSE; + BOOL is_copyable = FALSE; + BOOL is_complete = FALSE; + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType, 0); // TODO: MULTI-WEARABLE + if(item) + { + const LLPermissions& perm = item->getPermissions(); + is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); + is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()); + is_complete = item->isComplete(); + } + + childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty); + childSetEnabled("Save As", is_copyable && is_complete && has_wearable); + childSetEnabled("Revert", has_wearable && is_dirty ); + childSetEnabled("Take Off", has_wearable ); + childSetVisible("Take Off", mCanTakeOff && has_wearable ); + childSetVisible("Create New", !has_wearable ); + + childSetVisible("not worn instructions", !has_wearable ); + childSetVisible("no modify instructions", has_wearable && !is_modifiable); + + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (wearable_entry) + { + U8 num_subparts = wearable_entry->mSubparts.size(); + + for (U8 index = 0; index < num_subparts; ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (!subpart_entry) + { + llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + continue; + } + + childSetVisible(subpart_entry->mButtonName,has_wearable); + if( has_wearable && is_complete && is_modifiable ) + { + childSetEnabled(subpart_entry->mButtonName, subpart_entry->mSex & avatar->getSex() ); + } + else + { + childSetEnabled(subpart_entry->mButtonName, FALSE ); + } + } + } + + childSetVisible("square", !is_modifiable); + + childSetVisible("title", FALSE); + childSetVisible("title_no_modify", FALSE); + childSetVisible("title_not_worn", FALSE); + childSetVisible("title_loading", FALSE); + + childSetVisible("path", FALSE); + + LLTextBox *av_height = getChild("avheight",FALSE,FALSE); + if(av_height) //Only display this if the element exists + { + // Display the shape's nominal height. + // + // The value for avsize is the best available estimate from + // measuring against prims. + float avsize = avatar->mBodySize.mV[VZ] + .195; + int inches = (int)(avsize / .0254f); + int feet = inches / 12; + inches %= 12; + + std::ostringstream avheight(std::ostringstream::trunc); + avheight << std::fixed << std::setprecision(2) << avsize << " m (" + << feet << "' " << inches << "\")"; + av_height->setVisible(TRUE); + av_height->setTextArg("[AVHEIGHT]",avheight.str()); + } + + if(has_wearable && !is_modifiable) + { + // *TODO:Translate + childSetVisible("title_no_modify", TRUE); + childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); + + hideTextureControls(); + } + else if(has_wearable && !is_complete) + { + // *TODO:Translate + childSetVisible("title_loading", TRUE); + childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); + + std::string path; + const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE + append_path(item_id, path); + childSetVisible("path", TRUE); + childSetTextArg("path", "[PATH]", path); + + hideTextureControls(); + } + else if(has_wearable && is_modifiable) + { + childSetVisible("title", TRUE); + childSetTextArg("title", "[DESC]", wearable->getName() ); + + std::string path; + const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE + append_path(item_id, path); + childSetVisible("path", TRUE); + childSetTextArg("path", "[PATH]", path); + + for_each_picker_ctrl_entry (this, mType, boost::bind(update_color_swatch_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(update_texture_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, is_copyable && is_complete, this, _1, _2)); + } + else + { + // *TODO:Translate + childSetVisible("title_not_worn", TRUE); + childSetTextArg("title_not_worn", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); + + hideTextureControls(); + } + + childSetVisible("icon", has_wearable && is_modifiable); + + LLPanel::draw(); +} + +void LLPanelEditWearable::setVisible(BOOL visible) +{ + LLPanel::setVisible( visible ); + if( !visible ) + { + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); + } +} + +// static +void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete) +{ + if( wearable ) + { + setUIPermissions(perm_mask, is_complete); + if (mType == LLWearableType::WT_ALPHA) + { + initPreviousTextureList(); + } + } +} + +// static +void LLPanelEditWearable::onRevertButtonClicked( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + gAgentWearables.revertWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE +} + +void LLPanelEditWearable::onBtnSave( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + gAgentWearables.saveWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE +} + +// static +void LLPanelEditWearable::onBtnSaveAs( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLWearable* wearable = gAgentWearables.getWearable( self->getType(), 0 ); // TODO: MULTI-WEARABLE + if( wearable ) + { + LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self ); + save_as_dialog->startModal(); + // LLWearableSaveAsDialog deletes itself. + } +} + +// static +void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLVOAvatar* avatar = gAgentAvatarp; + if( avatar ) + { + gAgentWearables.saveWearableAs( self->getType(), 0, save_as_dialog->getItemName(), FALSE ); // TODO: MULTI-WEARABLE + } +} + +// static +void LLPanelEditWearable::onCommitSexChange() +{ + if (!isAgentAvatarValid()) return; + + LLWearableType::EType type = mType; // TODO: MULTI-WEARABLE + U32 index = 0; // TODO: MULTI-WEARABLE + + if( !gAgentWearables.isWearableModifiable(type, index)) + { + return; + } + + LLViewerVisualParam* param = static_cast(gAgentAvatarp->getVisualParam( "male" )); + if( !param ) + { + return; + } + + bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE; + LLWearable* wearable = gAgentWearables.getWearable(type, index); + if (wearable) + { + wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE); + } + param->setWeight( is_new_sex_male, FALSE ); + + gAgentAvatarp->updateSexDependentLayerSets( FALSE ); + + gAgentAvatarp->updateVisualParams(); + + + //if(!wearable) + //{ + // return; + //} + + + + //wearable->setVisualParamWeight(param->getID(), (new_sex == SEX_MALE), TRUE); + //wearable->writeToAvatar(); + //avatar->updateVisualParams(); + + gFloaterCustomize->clearScrollingPanelList(); + + // Assumes that we're in the "Shape" Panel. + //self->setSubpart( SUBPART_SHAPE_WHOLE ); +} + + +// static +void LLPanelEditWearable::onBtnCreateNew( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLSD payload; + payload["wearable_type"] = (S32)self->getType(); + LLNotificationsUtil::add("AutoWearNewClothing", LLSD(), payload, &onSelectAutoWearOption); +} + +bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLVOAvatar* avatar = gAgentAvatarp; + if(avatar) + { + // Create a new wearable in the default folder for the wearable's asset type. + LLWearable* wearable = LLWearableList::instance().createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger() ); + LLAssetType::EType asset_type = wearable->getAssetType(); + + LLUUID folder_id; + // regular UI, items get created in normal folder + folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); + + // Only auto wear the new item if the AutoWearNewClothing checkbox is selected. + LLPointer cb = option == 0 ? + new WearOnAvatarCallback : NULL; + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), + asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), cb); + } + return false; +} + + +bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) +{ + const LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE + if(wearable) + { + const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); + return (lto && lto->getID() == IMG_INVISIBLE); + } + return false; +} + +LLWearable* LLPanelEditWearable::getWearable() const +{ + return gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE +} + + +void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) +{ + const LLTextureCtrl* texture_ctrl = dynamic_cast(ctrl); + if (!texture_ctrl) + { + llwarns << "got commit signal from not LLTextureCtrl." << llendl; + return; + } + + if (getWearable()) + { + LLWearableType::EType type = getWearable()->getType(); + const PickerControlEntryNamePredicate name_pred(texture_ctrl->getName()); + const LLEditWearableDictionary::PickerControlEntry* entry + = find_picker_ctrl_entry_if(type, name_pred); + if (entry) + { + // Set the new version + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID()); + if( image->getID() == IMG_DEFAULT ) + { + image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); + } + if (getWearable()) + { + U32 index = gAgentWearables.getWearableIndex(getWearable()); + gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index); + LLVisualParamHint::requestHintUpdates(); + gAgentAvatarp->wearableUpdated(type, FALSE); + } + if (mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) + { + mPreviousTextureList[entry->mTextureIndex] = image->getID(); + } + } + else + { + llwarns << "could not get texture picker dictionary entry for wearable of type: " << type << llendl; + } + } +} + +void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* base_ctrl ) +{ + LLColorSwatchCtrl* ctrl = (LLColorSwatchCtrl*) base_ctrl; + + if (getWearable()) + { + LLWearableType::EType type = getWearable()->getType(); + const PickerControlEntryNamePredicate name_pred(ctrl->getName()); + const LLEditWearableDictionary::PickerControlEntry* entry + = find_picker_ctrl_entry_if(type, name_pred); + if (entry) + { + const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex); + const LLColor4& new_color = LLColor4(ctrl->getValue()); + if( old_color != new_color ) + { + getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); + LLVisualParamHint::requestHintUpdates(); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } + } + else + { + llwarns << "could not get color swatch dictionary entry for wearable of type: " << type << llendl; + } + } +} + +ESubpart LLPanelEditWearable::getDefaultSubpart() +{ + switch( mType ) + { + case LLWearableType::WT_SHAPE: return SUBPART_SHAPE_WHOLE; + case LLWearableType::WT_SKIN: return SUBPART_SKIN_COLOR; + case LLWearableType::WT_HAIR: return SUBPART_HAIR_COLOR; + case LLWearableType::WT_EYES: return SUBPART_EYES; + case LLWearableType::WT_SHIRT: return SUBPART_SHIRT; + case LLWearableType::WT_PANTS: return SUBPART_PANTS; + case LLWearableType::WT_SHOES: return SUBPART_SHOES; + case LLWearableType::WT_SOCKS: return SUBPART_SOCKS; + case LLWearableType::WT_JACKET: return SUBPART_JACKET; + case LLWearableType::WT_GLOVES: return SUBPART_GLOVES; + case LLWearableType::WT_UNDERSHIRT: return SUBPART_UNDERSHIRT; + case LLWearableType::WT_UNDERPANTS: return SUBPART_UNDERPANTS; + case LLWearableType::WT_SKIRT: return SUBPART_SKIRT; + case LLWearableType::WT_ALPHA: return SUBPART_ALPHA; + case LLWearableType::WT_TATTOO: return SUBPART_TATTOO; + case LLWearableType::WT_PHYSICS: return SUBPART_PHYSICS_BELLY_UPDOWN; + + default: llassert(0); return SUBPART_SHAPE_WHOLE; + } +} + + + + +void LLPanelEditWearable::hideTextureControls() +{ + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, FALSE, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, FALSE, this, _1, _2)); +} + + +void LLPanelEditWearable::switchToDefaultSubpart() +{ + setSubpart( getDefaultSubpart() ); +} + + + +void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) +{ + BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE; + BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE; + + childSetEnabled("Save", is_modifiable && is_complete); + childSetEnabled("Save As", is_copyable && is_complete); + childSetEnabled("sex radio", is_modifiable && is_complete); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_copyable && is_modifiable && is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_modifiable && is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, is_copyable && is_modifiable && is_complete, this, _1, _2)); +} + +// static +void LLPanelEditWearable::onBtnSubpart(void* userdata) +{ + LLFloaterCustomize* floater_customize = gFloaterCustomize; + if (!floater_customize) return; + LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel(); + if (!self) return; + ESubpart subpart = (ESubpart) (intptr_t)userdata; + self->setSubpart( subpart ); +} + +void LLPanelEditWearable::setSubpart( ESubpart subpart ) +{ + mCurrentSubpart = subpart; + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (wearable_entry) + { + U8 num_subparts = wearable_entry->mSubparts.size(); + + for (U8 index = 0; index < num_subparts; ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (subpart_entry) + { + LLButton* btn = getChild(subpart_entry->mButtonName); + { + btn->setToggleState( subpart == subpart_e ); + } + } + } + } + + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart); + if( subpart_entry ) + { + // Update the thumbnails we display + LLFloaterCustomize::param_map sorted_params; + LLVOAvatar* avatar = gAgentAvatarp; + ESex avatar_sex = avatar->getSex(); + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType,0); // TODO: MULTI-WEARABLE + U32 perm_mask = 0x0; + BOOL is_complete = FALSE; + bool can_export = false; + bool can_import = false; + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + + if (subpart <= 18) // body parts only + { + can_import = true; + + if (is_complete && + gAgent.getID() == item->getPermissions().getOwner() && + gAgent.getID() == item->getPermissions().getCreator() && + (PERM_ITEM_UNRESTRICTED & + perm_mask) == PERM_ITEM_UNRESTRICTED) + { + can_export = true; + } + } + } + setUIPermissions(perm_mask, is_complete); + BOOL editable = ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE; + + for(LLViewerVisualParam* param = (LLViewerVisualParam *)avatar->getFirstVisualParam(); + param; + param = (LLViewerVisualParam *)avatar->getNextVisualParam()) + { + if (param->getID() == -1 + || !param->isTweakable() + || param->getEditGroup() != subpart_entry->mEditGroup + || !(param->getSex() & avatar_sex)) + { + continue; + } + + // negative getDisplayOrder() to make lowest order the highest priority + LLFloaterCustomize::param_map::value_type vt(-param->getDisplayOrder(), LLFloaterCustomize::editable_param(editable, param)); + llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates + sorted_params.insert(vt); + } + gFloaterCustomize->generateVisualParamHints(NULL, sorted_params, mType != LLWearableType::WT_PHYSICS); + gFloaterCustomize->updateScrollingPanelUI(); + gFloaterCustomize->childSetEnabled("Export", can_export); + gFloaterCustomize->childSetEnabled("Import", can_import); + + // Update the camera + gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) ); + gMorphView->setCameraTargetOffset( subpart_entry->mTargetOffset ); + gMorphView->setCameraOffset( subpart_entry->mCameraOffset ); + gMorphView->setCameraDistToDefault(); + if (gSavedSettings.getBOOL("AppearanceCameraMovement")) + { + gMorphView->updateCamera(); + } + } +} + +// static +void LLPanelEditWearable::onBtnTakeOff( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + + LLWearable* wearable = gAgentWearables.getWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE + if( !wearable ) + { + return; + } + + gAgentWearables.removeWearable( self->mType, false, 0 ); // TODO: MULTI-WEARABLE +} + +// static +void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLCheckBoxCtrl* checkbox_ctrl = (LLCheckBoxCtrl*) ctrl; + if (!gAgentAvatarp) + { + return; + } + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(self->mType); + if (wearable_entry) + { + U8 num_textures = wearable_entry->mTextureCtrls.size(); + + for (U8 index = 0; index < num_textures; ++index) + { + // dive into data structures to get the panel we need + ETextureIndex texindex = wearable_entry->mTextureCtrls[index]; + + const LLEditWearableDictionary::PickerControlEntry *tex_ctrl = LLEditWearableDictionary::getInstance()->getTexturePicker(texindex); + + if (tex_ctrl && tex_ctrl->mCheckboxName == checkbox_ctrl->getName()) + { + bool new_invis_state = checkbox_ctrl->get(); + if (new_invis_state) + { + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); + + LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE + const LLLocalTextureObject* lto = wearable ? wearable->getLocalTextureObject(texindex) : NULL; + + if(lto) + { + self->mPreviousTextureList[(S32)texindex] = lto->getID(); + } + if(wearable) + { + LLLocalTextureObject new_lto(image, IMG_INVISIBLE); + wearable->setLocalTextureObject(texindex, new_lto); + wearable->writeToAvatar(); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); + } + + } + else + { + // Try to restore previous texture, if any. + LLUUID prev_id = self->mPreviousTextureList[(S32)texindex]; + if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) + { + prev_id = LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")); + } + if (prev_id.notNull()) + { + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); + LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE + if(wearable) + { + LLLocalTextureObject new_lto(image, prev_id); + wearable->setLocalTextureObject(texindex, new_lto); + wearable->writeToAvatar(); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); + } + } + } + } + } + } +} + +void LLPanelEditWearable::initPreviousTextureList() +{ + initPreviousTextureListEntry(TEX_LOWER_ALPHA); + initPreviousTextureListEntry(TEX_UPPER_ALPHA); + initPreviousTextureListEntry(TEX_HEAD_ALPHA); + initPreviousTextureListEntry(TEX_EYES_ALPHA); + initPreviousTextureListEntry(TEX_LOWER_ALPHA); +} +void LLPanelEditWearable::initPreviousTextureListEntry(ETextureIndex te) +{ + if(!getWearable()) + return; + LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te); + if (lto) + { + mPreviousTextureList[te] = lto->getID(); + } +} diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h new file mode 100644 index 000000000..808296211 --- /dev/null +++ b/indra/newview/llpaneleditwearable.h @@ -0,0 +1,114 @@ +/** + * @file llpaneleditwearable.h + * @brief A LLPanel dedicated to the editing of wearables. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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_LLPANELEDITWEARABLE_H +#define LL_LLPANELEDITWEARABLE_H + +#include "llpanel.h" +#include "llscrollingpanellist.h" +#include "llmodaldialog.h" +#include "llvoavatardefines.h" +#include "llwearabletype.h" + +class LLAccordionCtrl; +class LLCheckBoxCtrl; +class LLWearable; +class LLTextBox; +class LLViewerInventoryItem; +class LLViewerVisualParam; +class LLVisualParamHint; +class LLViewerJointMesh; +class LLAccordionCtrlTab; +class LLJoint; +class LLLineEditor; +class LLSubpart; +class LLWearableSaveAsDialog; + +enum ESubpart; +using namespace LLVOAvatarDefines; + +class LLPanelEditWearable : public LLPanel +{ +public: + LLPanelEditWearable( LLWearableType::EType type ); + virtual ~LLPanelEditWearable(); + + virtual BOOL postBuild(); + virtual void draw(); + virtual BOOL isDirty() const; // LLUICtrl + + void addTextureDropTarget( ETextureIndex te, const std::string& name, const LLUUID& default_image_id, BOOL allow_no_texture ); + void addInvisibilityCheckbox(ETextureIndex te, const std::string& name); + + const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); } + LLWearableType::EType getType() const{ return mType; } + LLWearable* getWearable() const; + + ESubpart getDefaultSubpart(); + void setSubpart( ESubpart subpart ); + void switchToDefaultSubpart(); + + void setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete); + + void setUIPermissions(U32 perm_mask, BOOL is_complete); + + void hideTextureControls(); + bool textureIsInvisible(ETextureIndex te); + void initPreviousTextureList(); + void initPreviousTextureListEntry(ETextureIndex te); + + static void onRevertButtonClicked( void* userdata ); + void onCommitSexChange(); + + virtual void setVisible( BOOL visible ); + + // Callbacks + static void onBtnSubpart( void* userdata ); + static void onBtnTakeOff( void* userdata ); + static void onBtnSave( void* userdata ); + + static void onBtnSaveAs( void* userdata ); + static void onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ); + + static void onBtnTakeOffDialog( S32 option, void* userdata ); + static void onBtnCreateNew( void* userdata ); + static void onInvisibilityCommit( LLUICtrl* ctrl, void* userdata ); + static bool onSelectAutoWearOption(const LLSD& notification, const LLSD& response); + + + + void onColorSwatchCommit(const LLUICtrl*); + void onTexturePickerCommit(const LLUICtrl*); +private: + + LLWearableType::EType mType; + BOOL mCanTakeOff; + std::map mInvisibilityList; + std::map mPreviousTextureList; + ESubpart mCurrentSubpart; +}; + +#endif diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp new file mode 100644 index 000000000..5b142c571 --- /dev/null +++ b/indra/newview/llscrollingpanelparam.cpp @@ -0,0 +1,329 @@ +/** + * @file llscrollingpanelparam.cpp + * @brief UI panel for a list of visual param panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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" + +#include "llscrollingpanelparam.h" +#include "llviewerjointmesh.h" +#include "llviewervisualparam.h" +#include "llwearable.h" +#include "llviewervisualparam.h" +#include "lltoolmorph.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llviewborder.h" +#include "llvoavatarself.h" +#include "llagentwearables.h" +#include "llfloatercustomize.h" + +// Constants for LLPanelVisualParam +const F32 LLScrollingPanelParam::PARAM_STEP_TIME_THRESHOLD = 0.25f; + +const S32 LLScrollingPanelParam::PARAM_HINT_WIDTH = 128; +const S32 LLScrollingPanelParam::PARAM_HINT_HEIGHT = 128; + +const S32 BTN_BORDER = 2; +const S32 PARAM_HINT_LABEL_HEIGHT = 16; +const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + LLScrollingPanelParam::PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH); +const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + LLScrollingPanelParam::PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; + +// LLScrollingPanelParam +//static +S32 LLScrollingPanelParam::sUpdateDelayFrames = 0; + +LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ) + : LLScrollingPanelParamBase( name, mesh, param, allow_modify, bVisualHint, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 )), + mLess(NULL), + mMore(NULL) +{ + + if(bVisualHint) + { + S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; + S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT; + F32 min_weight = param->getMinWeight(); + F32 max_weight = param->getMaxWeight(); + + mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight); + pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; + mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight ); + + mHintMin->setAllowsUpdates( FALSE ); + mHintMax->setAllowsUpdates( FALSE ); + + // *TODO::translate + std::string min_name = param->getMinDisplayName(); + std::string max_name = param->getMaxDisplayName(); + childSetValue("min param text", min_name); + childSetValue("max param text", max_name); + mLess = getChild("less"); + mLess->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, false) ); + mLess->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, false) ); + mLess->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, false) ); + mLess->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + + mMore = getChild("more"); + mMore->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, true) ); + mMore->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, true) ); + mMore->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, true) ); + mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + } + + setVisible(FALSE); + setBorderVisible( FALSE ); +} + +LLScrollingPanelParam::~LLScrollingPanelParam() +{ + mHintMin = NULL; + mHintMax = NULL; +} + +void LLScrollingPanelParam::updatePanel(BOOL allow_modify) +{ + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE + + if(!wearable) + { + // not editing a wearable just now, no update necessary + return; + } + + LLScrollingPanelParamBase::updatePanel(allow_modify); + + if(mHintMin) + mHintMin->requestUpdate( sUpdateDelayFrames++ ); + if(mHintMax) + mHintMax->requestUpdate( sUpdateDelayFrames++ ); + + if(mLess) + mLess->setEnabled(mAllowModify); + if(mMore) + mMore->setEnabled(mAllowModify); +} + +void LLScrollingPanelParam::setVisible( BOOL visible ) +{ + if( getVisible() != visible ) + { + LLPanel::setVisible( visible ); + if(mHintMin) + mHintMin->setAllowsUpdates( visible ); + if(mHintMax) + mHintMax->setAllowsUpdates( visible ); + + if( visible ) + { + if(mHintMin) + mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ ); + if(mHintMax) + mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ ); + } + } +} + +void LLScrollingPanelParam::draw() +{ + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE + + if( !wearable || gFloaterCustomize->isMinimized() ) + { + return; + } + + if(mLess) + mLess->setVisible(mHintMin && mHintMin->getVisible()); + if(mMore) + mMore->setVisible(mHintMax && mHintMax->getVisible()); + + // Draw all the children except for the labels + childSetVisible( "min param text", FALSE ); + childSetVisible( "max param text", FALSE ); + LLPanel::draw(); + + // Draw the hints over the "less" and "more" buttons. + if(mHintMin) + { + gGL.pushMatrix(); + { + const LLRect& r = mHintMin->getRect(); + F32 left = (F32)(r.mLeft + BTN_BORDER); + F32 bot = (F32)(r.mBottom + BTN_BORDER); + gGL.translatef(left, bot, 0.f); + mHintMin->draw(); + } + gGL.popMatrix(); + } + + if(mHintMax) + { + gGL.pushMatrix(); + { + const LLRect& r = mHintMax->getRect(); + F32 left = (F32)(r.mLeft + BTN_BORDER); + F32 bot = (F32)(r.mBottom + BTN_BORDER); + gGL.translatef(left, bot, 0.f); + mHintMax->draw(); + } + gGL.popMatrix(); + } + + + // Draw labels on top of the buttons + childSetVisible( "min param text", TRUE ); + drawChild(getChild("min param text"), BTN_BORDER, BTN_BORDER); + + childSetVisible( "max param text", TRUE ); + drawChild(getChild("max param text"), BTN_BORDER, BTN_BORDER); +} + +// static +void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata) +{ +} + +// static +void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata) +{ + LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; + LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); +} + +void LLScrollingPanelParam::onHintMouseDown( bool max ) +{ + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + LLViewerVisualParam* param = hint->getVisualParam(); + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE + + if(!wearable || !param) + { + return; + } + + // morph towards this result + F32 current_weight = wearable->getVisualParamWeight( hint->getVisualParam()->getID() ); + + // if we have maxed out on this morph, we shouldn't be able to click it + if( hint->getVisualParamWeight() != current_weight ) + { + mMouseDownTimer.reset(); + mLastHeldTime = 0.f; + } +} + +void LLScrollingPanelParam::onHintHeldDown( bool max ) +{ + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + LLViewerVisualParam* param = hint->getVisualParam(); + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE + + if(!wearable || !param) + { + return; + } + + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + + if (current_weight != hint->getVisualParamWeight() ) + { + const F32 FULL_BLEND_TIME = 2.f; + F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime; + mLastHeldTime += elapsed_time; + + F32 new_weight; + if (current_weight > hint->getVisualParamWeight() ) + { + new_weight = current_weight - (elapsed_time / FULL_BLEND_TIME); + } + else + { + new_weight = current_weight + (elapsed_time / FULL_BLEND_TIME); + } + + // Make sure we're not taking the slider out of bounds + // (this is where some simple UI limits are stored) + F32 new_percent = weightToPercent(new_weight); + LLSliderCtrl* slider = getChild("param slider"); + if (slider) + { + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + wearable->setVisualParamWeight(param->getID(), new_weight, FALSE); + wearable->writeToAvatar(); + gAgentAvatarp->updateVisualParams(); + + slider->setValue( weightToPercent( new_weight ) ); + } + } + } +} + +void LLScrollingPanelParam::onHintMouseUp( bool max ) +{ + F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32(); + + if (isAgentAvatarValid()) + { + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + + if (elapsed_time < PARAM_STEP_TIME_THRESHOLD) + { + LLViewerVisualParam* param = hint->getVisualParam(); + + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE + if(wearable) + { + // step in direction + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + F32 range = mHintMax->getVisualParamWeight() - mHintMin->getVisualParamWeight(); + //if min, range should be negative. + if(!max) + range *= -1.f; + // step a fraction in the negative direction + F32 new_weight = current_weight + (range / 10.f); + F32 new_percent = weightToPercent(new_weight); + LLSliderCtrl* slider = getChild("param slider"); + if (slider) + { + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + wearable->setVisualParamWeight(param->getID(), new_weight, FALSE); + wearable->writeToAvatar(); + slider->setValue( weightToPercent( new_weight ) ); + } + } + } + } + } + + LLVisualParamHint::requestHintUpdates( mHintMin, mHintMax ); +} + diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h new file mode 100644 index 000000000..4b2069574 --- /dev/null +++ b/indra/newview/llscrollingpanelparam.h @@ -0,0 +1,76 @@ +/** + * @file llscrollingpanelparam.h + * @brief the scrolling panel containing a list of visual param + * panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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_SCROLLINGPANELPARAM_H +#define LL_SCROLLINGPANELPARAM_H + +#include "llscrollingpanelparambase.h" + +class LLViewerJointMesh; +class LLViewerVisualParam; +class LLWearable; +class LLVisualParamHint; +class LLViewerVisualParam; +class LLJoint; + +class LLScrollingPanelParam : public LLScrollingPanelParamBase +{ +public: + LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ); + virtual ~LLScrollingPanelParam(); + + virtual void draw(); + virtual void setVisible( BOOL visible ); + virtual void updatePanel(BOOL allow_modify); + + static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata); + static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata); + + void onHintMouseUp( bool max ); + void onHintMouseDown( bool max ); + void onHintHeldDown( bool max ); + +public: + // Constants for LLPanelVisualParam + const static F32 PARAM_STEP_TIME_THRESHOLD; + + const static S32 PARAM_HINT_WIDTH; + const static S32 PARAM_HINT_HEIGHT; + LLPointer mHintMin; + LLPointer mHintMax; + LLButton* mLess; + LLButton* mMore; + static S32 sUpdateDelayFrames; + +protected: + LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. + F32 mLastHeldTime; + BOOL mAllowModify; +}; + + +#endif diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp new file mode 100644 index 000000000..bd8561cf6 --- /dev/null +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -0,0 +1,139 @@ +/** + * @file llscrollingpanelparam.cpp + * @brief UI panel for a list of visual param panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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" + +#include "llscrollingpanelparambase.h" +#include "llviewerjointmesh.h" +#include "llviewervisualparam.h" +#include "llwearable.h" +#include "llviewervisualparam.h" +#include "lltoolmorph.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llviewborder.h" +#include "llvoavatarself.h" +#include "llagentwearables.h" + +LLScrollingPanelParamBase::LLScrollingPanelParamBase( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint, LLRect rect ) + : LLScrollingPanel( name, rect ), + mParam(param), + mAllowModify(allow_modify) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); + //Set up the slider + LLSliderCtrl *slider = getChild("param slider"); + + //Kill everything that isn't the slider... + if(!bVisualHint) + { + child_list_t to_remove; + child_list_t::const_iterator it; + for (it = getChildList()->begin(); it != getChildList()->end(); it++) + { + if ((*it) != slider && (*it)->getName() != "panel border") + { + to_remove.push_back(*it); + } + } + for (it = to_remove.begin(); it != to_remove.end(); it++) + { + removeChild(*it); + delete (*it); + } + slider->translate(0,/*PARAM_HINT_HEIGHT*/128); + reshape(getRect().getWidth(),getRect().getHeight()-128); + } + + slider->setValue(weightToPercent(param->getWeight())); + slider->setLabelArg("[DESC]", param->getDisplayName()); + slider->setEnabled(mAllowModify); + slider->setCommitCallback(boost::bind(&LLScrollingPanelParamBase::onSliderMoved, this, _1)); + + setVisible(FALSE); + setBorderVisible( FALSE ); +} + +LLScrollingPanelParamBase::~LLScrollingPanelParamBase() +{ +} + +void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify) +{ + LLViewerVisualParam* param = mParam; + LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)param->getWearableType(), 0 ); // TODO: MULTI-WEARABLE + if(!wearable) + { + // not editing a wearable just now, no update necessary + return; + } + + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + childSetValue("param slider", weightToPercent( current_weight ) ); + mAllowModify = allow_modify; + childSetEnabled("param slider", mAllowModify); +} + +void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl) +{ + if(!mParam) + { + return; + } + + LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)mParam->getWearableType(), 0 ); // TODO: MULTI-WEARABLE + + if(!wearable) + { + return; + } + + LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; + + F32 current_weight = wearable->getVisualParamWeight(mParam->getID()); + F32 new_weight = percentToWeight( (F32)slider->getValue().asReal() ); + if (current_weight != new_weight ) + { + wearable->setVisualParamWeight( mParam->getID(), new_weight, FALSE); + wearable->writeToAvatar(); + gAgentAvatarp->updateVisualParams(); + } +} + +F32 LLScrollingPanelParamBase::weightToPercent( F32 weight ) +{ + LLViewerVisualParam* param = mParam; + return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; +} + +F32 LLScrollingPanelParamBase::percentToWeight( F32 percent ) +{ + LLViewerVisualParam* param = mParam; + return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); +} diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h new file mode 100644 index 000000000..9f41882c6 --- /dev/null +++ b/indra/newview/llscrollingpanelparambase.h @@ -0,0 +1,61 @@ +/** + * @file llscrollingpanelparam.h + * @brief the scrolling panel containing a list of visual param + * panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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_SCROLLINGPANELPARAMBASE_H +#define LL_SCROLLINGPANELPARAMBASE_H + +#include "llpanel.h" +#include "llscrollingpanellist.h" + +class LLViewerJointMesh; +class LLViewerVisualParam; +class LLWearable; +class LLVisualParamHint; +class LLViewerVisualParam; +class LLJoint; + +class LLScrollingPanelParamBase : public LLScrollingPanel +{ +public: + LLScrollingPanelParamBase( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint, LLRect rect ); + virtual ~LLScrollingPanelParamBase(); + + virtual void updatePanel(BOOL allow_modify); + + void onSliderMoved(LLUICtrl* ctrl); + + F32 weightToPercent( F32 weight ); + F32 percentToWeight( F32 percent ); + +public: + LLViewerVisualParam* mParam; +protected: + BOOL mAllowModify; +}; + +#endif diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index f95a8f085..30d716134 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -64,6 +64,7 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "pipeline.h" +#include "llagentwearables.h" //static @@ -152,7 +153,8 @@ BOOL LLVisualParamHint::needsRender() void LLVisualParamHint::preRender(BOOL clear_depth) { mLastParamWeight = mVisualParam->getWeight(); - //mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mVisualParam->getWearableType(),0); // TODO: MULTI-WEARABLE + if(wearable)wearable->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f); gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f); @@ -252,7 +254,10 @@ BOOL LLVisualParamHint::render() gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } - gAgentAvatarp->setVisualParamWeight(mVisualParam, mLastParamWeight); + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mVisualParam->getWearableType(),0); // TODO: MULTI-WEARABLE + if(wearable)wearable->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); + gAgentAvatarp->updateVisualParams(); gGL.color4f(1,1,1,1); mGLTexturep->setGLTextureCreated(true); return TRUE; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 1e12feb84..f44ac395a 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -1077,6 +1077,27 @@ void LLWearable::revertValues() { panel->updateScrollingPanelList(); }*/ + if( gFloaterCustomize ) + { + if(gAgentWearables.getWearableIndex(this) != 0) // TODO: MULTI-WEARABLE + return; + + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(getItemID()); // TODO: MULTI-WEARABLE + U32 perm_mask = PERM_NONE; + BOOL is_complete = FALSE; + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + if(!is_complete) + { + item->fetchFromServer(); + } + } + gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); + LLFloaterCustomize::setCurrentWearableType( mType ); + } } BOOL LLWearable::isOnTop() const @@ -1118,6 +1139,28 @@ void LLWearable::saveValues() { panel->updateScrollingPanelList(); }*/ + if( gFloaterCustomize ) + { + if(gAgentWearables.getWearableIndex(this) != 0) // TODO: MULTI-WEARABLE + return; + + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(getItemID()); // TODO: MULTI-WEARABLE + U32 perm_mask = PERM_NONE; + BOOL is_complete = FALSE; + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + if(!is_complete) + { + item->fetchFromServer(); + } + } + gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); + LLFloaterCustomize::setCurrentWearableType( mType ); + } + } void LLWearable::syncImages(te_map_t &src, te_map_t &dst)