llfloatercustomize.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llfloatercustomize.h"
00035 #include "llfontgl.h"
00036 #include "llbutton.h"
00037 #include "lliconctrl.h"
00038 #include "llresmgr.h"
00039 #include "llmorphview.h"
00040 #include "llfloatertools.h"
00041 #include "llagent.h"
00042 #include "lltoolmorph.h"
00043 #include "llvoavatar.h"
00044 #include "llradiogroup.h"
00045 #include "lltoolmgr.h"
00046 #include "llviewermenu.h"
00047 #include "llscrollcontainer.h"
00048 #include "llscrollingpanellist.h"
00049 #include "llsliderctrl.h"
00050 #include "lltabcontainervertical.h"
00051 #include "llviewerwindow.h"
00052 #include "llinventorymodel.h"
00053 #include "llinventoryview.h"
00054 #include "lltextbox.h"
00055 #include "lllineeditor.h"
00056 #include "llviewerimagelist.h"
00057 #include "llfocusmgr.h"
00058 #include "llviewerwindow.h"
00059 #include "llviewercamera.h"
00060 #include "llgenepool.h"
00061 #include "llappearance.h"
00062 #include "imageids.h"
00063 #include "llmodaldialog.h"
00064 #include "llassetstorage.h"
00065 #include "lltexturectrl.h"
00066 #include "lltextureentry.h"
00067 #include "llwearablelist.h"
00068 #include "llviewerinventory.h"
00069 #include "lldbstrings.h"
00070 #include "llcolorswatch.h"
00071 #include "llglheaders.h"
00072 #include "llui.h"
00073 #include "llviewermessage.h"
00074 #include "llimagejpeg.h"
00075 #include "llviewercontrol.h"
00076 #include "lluictrlfactory.h"
00077 
00078 #include "llfilepicker.h"
00079 
00080 //*TODO:translate : The ui xml for this really needs to be integrated with the appearance paramaters
00081 
00082 // Globals
00083 LLFloaterCustomize* gFloaterCustomize = NULL;
00084 
00085 const F32 PARAM_STEP_TIME_THRESHOLD = 0.25f;
00086 
00088 // LLUndoWearable
00089 
00090 class LLUndoWearable
00091         :       public LLUndoBuffer::LLUndoAction
00092 {
00093 protected:
00094         LLAppearance                    mAppearance;
00095 
00096 protected:
00097         LLUndoWearable() {};
00098         virtual ~LLUndoWearable(){};
00099 
00100 public:
00101         static LLUndoAction *create()   { return new LLUndoWearable(); }
00102 
00103         void                    setVisualParam(S32 param_id, F32 weight);
00104         void                    setColor( LLVOAvatar::ETextureIndex te, const LLColor4& color );
00105         void                    setTexture( LLVOAvatar::ETextureIndex te, const LLUUID& asset_id );
00106         void                    setWearable( EWearableType type );
00107 
00108         virtual void    undo() {applyUndoRedo();}
00109         virtual void    redo() {applyUndoRedo();}
00110         void                    applyUndoRedo();
00111 };
00112 
00113 
00115 // LLFloaterCustomizeObserver
00116 
00117 class LLFloaterCustomizeObserver : public LLInventoryObserver
00118 {
00119 public:
00120         LLFloaterCustomizeObserver(LLFloaterCustomize* fc) : mFC(fc) {}
00121         virtual ~LLFloaterCustomizeObserver() {}
00122         virtual void changed(U32 mask) { mFC->updateScrollingPanelUI(); }
00123 protected:
00124         LLFloaterCustomize* mFC;
00125 };
00126 
00128 
00129 // Local Constants 
00130 
00131 class LLWearableSaveAsDialog : public LLModalDialog
00132 {
00133 private:
00134         LLString        mItemName;
00135         void            (*mCommitCallback)(LLWearableSaveAsDialog*,void*);
00136         void*           mCallbackUserData;
00137 
00138 public:
00139         LLWearableSaveAsDialog( const LLString& desc, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata )
00140                 : LLModalDialog( "", 240, 100 ),
00141                   mCommitCallback( commit_cb ),
00142                   mCallbackUserData( userdata )
00143         {
00144                 LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml");
00145                 
00146                 childSetAction("Save", LLWearableSaveAsDialog::onSave, this );
00147                 childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this );
00148                 childSetTextArg("name ed", "[DESC]", desc);
00149         }
00150 
00151         virtual void startModal()
00152         {
00153                 LLModalDialog::startModal();
00154                 LLLineEditor* edit = getChild<LLLineEditor>("name ed");
00155                 if (!edit) return;
00156                 edit->setFocus(TRUE);
00157                 edit->selectAll();
00158         }
00159 
00160         const LLString& getItemName() { return mItemName; }
00161 
00162         static void onSave( void* userdata )
00163         {
00164                 LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata;
00165                 self->mItemName = self->childGetValue("name ed").asString();
00166                 LLString::trim(self->mItemName);
00167                 if( !self->mItemName.empty() )
00168                 {
00169                         if( self->mCommitCallback )
00170                         {
00171                                 self->mCommitCallback( self, self->mCallbackUserData );
00172                         }
00173                         self->close(); // destroys this object
00174                 }
00175         }
00176 
00177         static void onCancel( void* userdata )
00178         {
00179                 LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata;
00180                 self->close(); // destroys this object
00181         }
00182 };
00183 
00185 
00186 BOOL edit_wearable_for_teens(EWearableType type)
00187 {
00188         switch(type)
00189         {
00190         case WT_UNDERSHIRT:
00191         case WT_UNDERPANTS:
00192                 return FALSE;
00193         default:
00194                 return TRUE;
00195         }
00196 }
00197 
00198 class LLMakeOutfitDialog : public LLModalDialog
00199 {
00200 private:
00201         LLString        mFolderName;
00202         void            (*mCommitCallback)(LLMakeOutfitDialog*,void*);
00203         void*           mCallbackUserData;
00204         std::vector<std::pair<std::string,S32> > mCheckBoxList;
00205         
00206 public:
00207         LLMakeOutfitDialog( void(*commit_cb)(LLMakeOutfitDialog*,void*), void* userdata )
00208                 : LLModalDialog("",515, 510, TRUE ),
00209                   mCommitCallback( commit_cb ),
00210                   mCallbackUserData( userdata )
00211         {
00212                 LLUICtrlFactory::getInstance()->buildFloater(this, "floater_new_outfit_dialog.xml");
00213                 
00214                 // Build list of check boxes
00215                 for( S32 i = 0; i < WT_COUNT; i++ )
00216                 {
00217                         LLString name = LLString("checkbox_") + LLWearable::typeToTypeLabel( (EWearableType)i );
00218                         mCheckBoxList.push_back(std::make_pair(name,i));
00219                         // Hide teen items
00220                         if (gAgent.isTeen() &&
00221                                 !edit_wearable_for_teens((EWearableType)i))
00222                         {
00223                                 // hide wearable checkboxes that don't apply to this account
00224                                 LLString name = LLString("checkbox_") + LLWearable::typeToTypeLabel( (EWearableType)i );
00225                                 childSetVisible(name, FALSE);
00226                         }
00227                 }
00228 
00229                 // NOTE: .xml needs to be updated if attachments are added or their names are changed!
00230                 LLVOAvatar* avatar = gAgent.getAvatarObject();
00231                 if( avatar )
00232                 {
00233                         for (LLVOAvatar::attachment_map_t::iterator iter = avatar->mAttachmentPoints.begin(); 
00234                                  iter != avatar->mAttachmentPoints.end(); )
00235                         {
00236                                 LLVOAvatar::attachment_map_t::iterator curiter = iter++;
00237                                 LLViewerJointAttachment* attachment = curiter->second;
00238                                 S32     attachment_pt = curiter->first; 
00239                                 BOOL object_attached = ( attachment->getNumObjects() > 0 );
00240                                 LLString name = LLString("checkbox_") + attachment->getName();
00241                                 mCheckBoxList.push_back(std::make_pair(name,attachment_pt));
00242                                 childSetEnabled(name, object_attached);
00243                         }
00244                 }
00245 
00246                 childSetAction("Save", onSave, this ); 
00247                 childSetAction("Cancel", onCancel, this ); 
00248         }
00249 
00250         BOOL getRenameClothing()
00251         {
00252                 return childGetValue("rename").asBoolean();
00253 
00254         }
00255         virtual void draw()
00256         {
00257                 BOOL one_or_more_items_selected = FALSE;
00258                 for( S32 i = 0; i < (S32)mCheckBoxList.size(); i++ )
00259                 {
00260                         if( childGetValue(mCheckBoxList[i].first).asBoolean() )
00261                         {
00262                                 one_or_more_items_selected = TRUE;
00263                                 break;
00264                         }
00265                 }
00266 
00267                 childSetEnabled("Save", one_or_more_items_selected );
00268                 
00269                 LLModalDialog::draw();
00270         }
00271 
00272         const LLString& getFolderName() { return mFolderName; }
00273 
00274         void setWearableToInclude( S32 wearable, S32 enabled, S32 selected )
00275         {
00276                 if( (0 <= wearable) && (wearable < WT_COUNT) )
00277                 {
00278                         LLString name = LLString("checkbox_") + LLWearable::typeToTypeLabel( (EWearableType)wearable );
00279                         childSetEnabled(name, enabled);
00280                         childSetValue(name, selected);
00281                 }
00282         }
00283 
00284         void getIncludedItems( LLDynamicArray<S32> &wearables_to_include, LLDynamicArray<S32> &attachments_to_include )
00285         {
00286                 for( S32 i = 0; i < (S32)mCheckBoxList.size(); i++)
00287                 {
00288                         LLString name = mCheckBoxList[i].first;
00289                         BOOL checked = childGetValue(name).asBoolean();
00290                         if (i < WT_COUNT )
00291                         {
00292                                 if( checked )
00293                                 {
00294                                         wearables_to_include.put(i);
00295                                 }
00296                         }
00297                         else
00298                         {
00299                                 if( checked )
00300                                 {
00301                                         S32 attachment_pt = mCheckBoxList[i].second;
00302                                         attachments_to_include.put( attachment_pt );
00303                                 }
00304                         }
00305                 }
00306         }
00307 
00308         static void onSave( void* userdata )
00309         {
00310                 LLMakeOutfitDialog* self = (LLMakeOutfitDialog*) userdata;
00311                 self->mFolderName = self->childGetValue("name ed").asString();
00312                 LLString::trim(self->mFolderName);
00313                 if( !self->mFolderName.empty() )
00314                 {
00315                         if( self->mCommitCallback )
00316                         {
00317                                 self->mCommitCallback( self, self->mCallbackUserData );
00318                         }
00319                         self->close(); // destroys this object
00320                 }
00321         }
00322 
00323         static void onCancel( void* userdata )
00324         {
00325                 LLMakeOutfitDialog* self = (LLMakeOutfitDialog*) userdata;
00326                 self->close(); // destroys this object
00327         }
00328 };
00329 
00331 // LLPanelEditWearable
00332 
00333 enum ESubpart {
00334         SUBPART_SHAPE_HEAD = 1, // avoid 0
00335         SUBPART_SHAPE_EYES,
00336         SUBPART_SHAPE_EARS,
00337         SUBPART_SHAPE_NOSE,
00338         SUBPART_SHAPE_MOUTH,
00339         SUBPART_SHAPE_CHIN,
00340         SUBPART_SHAPE_TORSO,
00341         SUBPART_SHAPE_LEGS,
00342         SUBPART_SHAPE_WHOLE,
00343         SUBPART_SHAPE_DETAIL,
00344         SUBPART_SKIN_COLOR,
00345         SUBPART_SKIN_FACEDETAIL,
00346         SUBPART_SKIN_MAKEUP,
00347         SUBPART_SKIN_BODYDETAIL,
00348         SUBPART_HAIR_COLOR,
00349         SUBPART_HAIR_STYLE,
00350         SUBPART_HAIR_EYEBROWS,
00351         SUBPART_HAIR_FACIAL,
00352         SUBPART_EYES,
00353         SUBPART_SHIRT,
00354         SUBPART_PANTS,
00355         SUBPART_SHOES,
00356         SUBPART_SOCKS,
00357         SUBPART_JACKET,
00358         SUBPART_GLOVES,
00359         SUBPART_UNDERSHIRT,
00360         SUBPART_UNDERPANTS,
00361         SUBPART_SKIRT
00362  };
00363 
00364 struct LLSubpart
00365 {
00366         LLSubpart() : mSex( SEX_BOTH ) {}
00367 
00368         LLString                        mButtonName;
00369         LLString                        mTargetJoint;
00370         LLString                        mEditGroup;
00371         LLVector3d                      mTargetOffset;
00372         LLVector3d                      mCameraOffset;
00373         ESex                            mSex;
00374 };
00375 
00377 
00378 class LLPanelEditWearable : public LLPanel, public LLEditMenuHandler
00379 {
00380 public:
00381         LLPanelEditWearable( EWearableType type );
00382         virtual ~LLPanelEditWearable();
00383 
00384         virtual BOOL            postBuild();
00385         virtual void            draw();
00386         virtual BOOL            isDirty() const;        // LLUICtrl
00387         
00388         void                            addSubpart(const LLString& name, ESubpart id, LLSubpart* part );
00389         void                            addTextureDropTarget( LLVOAvatar::ETextureIndex te, const LLString& name, const LLUUID& default_image_id, BOOL allow_no_texture );
00390         void                            addColorSwatch( LLVOAvatar::ETextureIndex te, const LLString& name );
00391 
00392         const char*                     getLabel()      { return LLWearable::typeToTypeLabel( mType ); }
00393         EWearableType           getType()       { return mType; }
00394 
00395         LLSubpart*                      getCurrentSubpart() { return mSubpartList[mCurrentSubpart]; }
00396         ESubpart                        getDefaultSubpart();
00397         void                            setSubpart( ESubpart subpart );
00398         void                            switchToDefaultSubpart();
00399 
00400         void                            setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete);
00401 
00402         void                            addVisualParamToUndoBuffer( S32 param_id, F32 current_weight );
00403 
00404         void                            setUIPermissions(U32 perm_mask, BOOL is_complete);
00405         
00406         virtual void            setVisible( BOOL visible );
00407 
00408         // Inherted methods from LLEditMenuHandler
00409         virtual void            undo()                  { mUndoBuffer->undoAction(); }
00410         virtual BOOL            canUndo() const { return mUndoBuffer->canUndo(); }
00411         virtual void            redo()                  { mUndoBuffer->redoAction(); }
00412         virtual BOOL            canRedo() const { return mUndoBuffer->canRedo(); }
00413 
00414         // Callbacks
00415         static void                     onBtnSubpart( void* userdata );
00416         static void                     onBtnTakeOff( void* userdata );
00417         static void                     onBtnRandomize( void* userdata );
00418         static void                     onBtnSave( void* userdata );
00419 
00420         static void                     onBtnSaveAs( void* userdata );
00421         static void                     onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata );
00422 
00423         static void                     onBtnRevert( void* userdata );
00424         static void                     onBtnTakeOffDialog( S32 option, void* userdata );
00425         static void                     onBtnCreateNew( void* userdata );
00426         static void                     onTextureCommit( LLUICtrl* ctrl, void* userdata );
00427         static void                     onColorCommit( LLUICtrl* ctrl, void* userdata );
00428         static void                     onCommitSexChange( LLUICtrl*, void* userdata );
00429         static void                     onSelectAutoWearOption(S32 option, void* data);
00430 
00431 
00432 
00433 private:
00434         EWearableType           mType;
00435         BOOL                            mCanTakeOff;
00436         std::map<LLString, S32> mTextureList;
00437         std::map<LLString, S32> mColorList;
00438         std::map<ESubpart, LLSubpart*> mSubpartList;
00439         ESubpart                        mCurrentSubpart;
00440         LLUndoBuffer*           mUndoBuffer;
00441 };
00442 
00444 
00445 LLPanelEditWearable::LLPanelEditWearable( EWearableType type )
00446         : LLPanel( LLWearable::typeToTypeLabel( type ) ),
00447           mType( type )
00448 {
00449         const S32 NUM_DISTORTION_UNDO_ENTRIES = 50;
00450         mUndoBuffer = new LLUndoBuffer(LLUndoWearable::create, NUM_DISTORTION_UNDO_ENTRIES);
00451 }
00452 
00453 BOOL LLPanelEditWearable::postBuild()
00454 {
00455         LLAssetType::EType asset_type = LLWearable::typeToAssetType( mType );
00456         LLString icon_name = (asset_type == LLAssetType::AT_CLOTHING ?
00457                                                                                  "inv_item_clothing.tga" :
00458                                                                                  "inv_item_skin.tga" );
00459         childSetValue("icon", icon_name);
00460 
00461         childSetAction("Create New", LLPanelEditWearable::onBtnCreateNew, this );
00462 
00463         // If PG, can't take off underclothing or shirt
00464         mCanTakeOff =
00465                 LLWearable::typeToAssetType( mType ) == LLAssetType::AT_CLOTHING &&
00466                 !( gAgent.isTeen() && (mType == WT_UNDERSHIRT || mType == WT_UNDERPANTS) );
00467         childSetVisible("Take Off", mCanTakeOff);
00468         childSetAction("Take Off", LLPanelEditWearable::onBtnTakeOff, this );
00469 
00470         childSetAction("Save",  &LLPanelEditWearable::onBtnSave, (void*)this );
00471 
00472         childSetAction("Save As", &LLPanelEditWearable::onBtnSaveAs, (void*)this );
00473 
00474         childSetAction("Revert", &LLPanelEditWearable::onBtnRevert, (void*)this );
00475 
00476         return TRUE;
00477 }
00478 
00479 LLPanelEditWearable::~LLPanelEditWearable()
00480 {
00481         delete mUndoBuffer;
00482 
00483         std::for_each(mSubpartList.begin(), mSubpartList.end(), DeletePairedPointer());
00484 
00485         // Route menu back to the default
00486         if( gEditMenuHandler == this )
00487         {
00488                 gEditMenuHandler = NULL;
00489         }
00490 }
00491 
00492 void LLPanelEditWearable::addSubpart( const LLString& name, ESubpart id, LLSubpart* part )
00493 {
00494         if (!name.empty())
00495         {
00496                 childSetAction(name, &LLPanelEditWearable::onBtnSubpart, (void*)id);
00497                 part->mButtonName = name;
00498         }
00499         mSubpartList[id] = part;
00500         
00501 }
00502 
00503 // static
00504 void LLPanelEditWearable::onBtnSubpart(void* userdata)
00505 {
00506         LLFloaterCustomize* floater_customize = gFloaterCustomize;
00507         if (!floater_customize) return;
00508         LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel();
00509         if (!self) return;
00510         ESubpart subpart = (ESubpart) (intptr_t)userdata;
00511         self->setSubpart( subpart );
00512 }
00513 
00514 void LLPanelEditWearable::setSubpart( ESubpart subpart )
00515 {
00516         mCurrentSubpart = subpart;
00517 
00518         for (std::map<ESubpart, LLSubpart*>::iterator iter = mSubpartList.begin();
00519                  iter != mSubpartList.end(); ++iter)
00520         {
00521                 LLButton* btn = getChild<LLButton>(iter->second->mButtonName);
00522                 if (btn)
00523                 {
00524                         btn->setToggleState( subpart == iter->first );
00525                 }
00526         }
00527 
00528         LLSubpart* part = get_if_there(mSubpartList, (ESubpart)subpart, (LLSubpart*)NULL);
00529         if( part )
00530         {
00531                 // Update the thumbnails we display
00532                 LLFloaterCustomize::param_map sorted_params;
00533                 LLVOAvatar* avatar = gAgent.getAvatarObject();
00534                 ESex avatar_sex = avatar->getSex();
00535                 LLViewerInventoryItem* item;
00536                 item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(mType);
00537                 U32 perm_mask = 0x0;
00538                 BOOL is_complete = FALSE;
00539                 if(item)
00540                 {
00541                         perm_mask = item->getPermissions().getMaskOwner();
00542                         is_complete = item->isComplete();
00543                 }
00544                 setUIPermissions(perm_mask, is_complete);
00545                 BOOL editable = ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE;
00546                 
00547                 for(LLViewerVisualParam* param = (LLViewerVisualParam *)avatar->getFirstVisualParam(); 
00548                         param; 
00549                         param = (LLViewerVisualParam *)avatar->getNextVisualParam())
00550                 {
00551                         if (param->getID() == -1
00552                                 || param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE 
00553                                 || param->getEditGroup() != part->mEditGroup 
00554                                 || !(param->getSex() & avatar_sex))
00555                         {
00556                                 continue;
00557                         }
00558 
00559                         // negative getDisplayOrder() to make lowest order the highest priority
00560                         LLFloaterCustomize::param_map::value_type vt(-param->getDisplayOrder(), LLFloaterCustomize::editable_param(editable, param));
00561                         llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() );  // Check for duplicates
00562                         sorted_params.insert(vt);
00563                 }
00564                 gFloaterCustomize->generateVisualParamHints(NULL, sorted_params);
00565                 gFloaterCustomize->updateScrollingPanelUI();
00566 
00567 
00568                 // Update the camera
00569                 gMorphView->setCameraTargetJoint( gAgent.getAvatarObject()->getJoint( part->mTargetJoint ) );
00570                 gMorphView->setCameraTargetOffset( part->mTargetOffset );
00571                 gMorphView->setCameraOffset( part->mCameraOffset );
00572                 gMorphView->setCameraDistToDefault();
00573                 if (gSavedSettings.getBOOL("AppearanceCameraMovement"))
00574                 {
00575                         gMorphView->updateCamera();
00576                 }
00577         }
00578 }
00579 
00580 // static
00581 void LLPanelEditWearable::onBtnRandomize( void* userdata )
00582 {
00583         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00584         
00585         LLVOAvatar* avatar = gAgent.getAvatarObject();
00586         LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(self->mType);
00587         if(avatar
00588            && item
00589            && item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID())
00590            && item->isComplete())
00591         {
00592                 // Save current wearable parameters and textures to the undo buffer.
00593                 LLUndoWearable* action = (LLUndoWearable*)(self->mUndoBuffer->getNextAction());
00594                 action->setWearable( self->mType );
00595 
00596                 ESex old_sex = avatar->getSex();
00597 
00598                 gFloaterCustomize->spawnWearableAppearance( self->mType );
00599                 
00600                 gFloaterCustomize->updateScrollingPanelList(TRUE);
00601 
00602                 ESex new_sex = avatar->getSex();
00603                 if( old_sex != new_sex )
00604                 {
00605                         // Updates radio button
00606                         gSavedSettings.setU32("AvatarSex", (new_sex == SEX_MALE) );
00607 
00608                         // Assumes that we're in the "Shape" Panel.
00609                         self->setSubpart( SUBPART_SHAPE_WHOLE );
00610                 }       
00611         }
00612 }
00613 
00614 
00615 // static
00616 void LLPanelEditWearable::onBtnTakeOff( void* userdata )
00617 {
00618         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00619         
00620         LLWearable* wearable = gAgent.getWearable( self->mType );
00621         if( !wearable )
00622         {
00623                 return;
00624         }
00625 
00626         gAgent.removeWearable( self->mType );
00627 }
00628 
00629 // static
00630 void LLPanelEditWearable::onBtnSave( void* userdata )
00631 {
00632         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00633         gAgent.saveWearable( self->mType );
00634 }
00635 
00636 // static
00637 void LLPanelEditWearable::onBtnSaveAs( void* userdata )
00638 {
00639         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00640         LLWearable* wearable = gAgent.getWearable( self->getType() );
00641         if( wearable )
00642         {
00643                 LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self );
00644                 save_as_dialog->startModal();
00645                 // LLWearableSaveAsDialog deletes itself.
00646         }
00647 }
00648 
00649 // static
00650 void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata )
00651 {
00652         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00653         LLVOAvatar* avatar = gAgent.getAvatarObject();
00654         if( avatar )
00655         {
00656                 gAgent.saveWearableAs( self->getType(), save_as_dialog->getItemName(), FALSE );
00657         }
00658 }
00659 
00660 
00661 // static
00662 void LLPanelEditWearable::onBtnRevert( void* userdata )
00663 {
00664         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00665         gAgent.revertWearable( self->mType );
00666 }
00667 
00668 // static
00669 void LLPanelEditWearable::onBtnCreateNew( void* userdata )
00670 {
00671         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00672         gViewerWindow->alertXml("AutoWearNewClothing", onSelectAutoWearOption, self);
00673 }
00674 void LLPanelEditWearable::onSelectAutoWearOption(S32 option, void* data)
00675 {
00676         LLPanelEditWearable* self = (LLPanelEditWearable*) data;
00677         LLVOAvatar* avatar = gAgent.getAvatarObject();
00678         if(avatar)
00679         {
00680                 // Create a new wearable in the default folder for the wearable's asset type.
00681                 LLWearable* wearable = gWearableList.createNewWearable( self->getType() );
00682                 LLAssetType::EType asset_type = wearable->getAssetType();
00683 
00684                 LLUUID folder_id;
00685                 // regular UI, items get created in normal folder
00686                 folder_id = gInventory.findCategoryUUIDForType(asset_type);
00687 
00688                 // Only auto wear the new item if the AutoWearNewClothing checkbox is selected.
00689                 LLPointer<LLInventoryCallback> cb = option == 0 ? 
00690                         new WearOnAvatarCallback : NULL;
00691                 create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
00692                         folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(),
00693                         asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(),
00694                         wearable->getPermissions().getMaskNextOwner(), cb);
00695         }
00696 }
00697 void LLPanelEditWearable::addColorSwatch( LLVOAvatar::ETextureIndex te, const LLString& name )
00698 {
00699         childSetCommitCallback(name, LLPanelEditWearable::onColorCommit, this);
00700         mColorList[name] = te;
00701 }
00702 
00703 // static
00704 void LLPanelEditWearable::onColorCommit( LLUICtrl* ctrl, void* userdata )
00705 {
00706         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00707         LLColorSwatchCtrl* color_ctrl = (LLColorSwatchCtrl*) ctrl;
00708 
00709         LLVOAvatar* avatar = gAgent.getAvatarObject();
00710         if( avatar )
00711         {
00712                 LLVOAvatar::ETextureIndex te = (LLVOAvatar::ETextureIndex)(self->mColorList[ctrl->getName()]);
00713 
00714                 LLColor4 old_color = avatar->getClothesColor( te );
00715                 const LLColor4& new_color = color_ctrl->get();
00716                 if( old_color != new_color )
00717                 {
00718                         // Save the old version to the undo stack
00719                         LLUndoWearable* action = (LLUndoWearable*)(self->mUndoBuffer->getNextAction());
00720                         action->setColor( te, old_color );
00721                         
00722                         // Set the new version
00723                         avatar->setClothesColor( te, new_color, TRUE );
00724                         gAgent.sendAgentSetAppearance();
00725 
00726                         LLVisualParamHint::requestHintUpdates();
00727                 }
00728         }
00729 }
00730 
00731 
00732 void LLPanelEditWearable::addTextureDropTarget( LLVOAvatar::ETextureIndex te, const LLString& name,
00733                                                                                                 const LLUUID& default_image_id, BOOL allow_no_texture )
00734 {
00735         childSetCommitCallback(name, LLPanelEditWearable::onTextureCommit, this);
00736         LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>(name);
00737         if (texture_ctrl)
00738         {
00739                 texture_ctrl->setDefaultImageAssetID(default_image_id);
00740                 texture_ctrl->setAllowNoTexture( allow_no_texture );
00741                 // Don't allow (no copy) or (no transfer) textures to be selected.
00742                 texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER);
00743                 texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER);
00744         }
00745         mTextureList[name] = te;
00746 }
00747 
00748 // static
00749 void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata )
00750 {
00751         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
00752         LLTextureCtrl* texture_ctrl = (LLTextureCtrl*) ctrl;
00753 
00754         LLVOAvatar* avatar = gAgent.getAvatarObject();
00755         if( avatar )
00756         {
00757                 LLVOAvatar::ETextureIndex te = (LLVOAvatar::ETextureIndex)(self->mTextureList[ctrl->getName()]);
00758 
00759                 // Save the old version to the undo stack
00760                 LLViewerImage* existing_image = avatar->getTEImage( te );
00761                 if( existing_image )
00762                 {
00763                         LLUndoWearable* action = (LLUndoWearable*)(self->mUndoBuffer->getNextAction());
00764                         action->setTexture( te, existing_image->getID() );
00765                 }
00766                 
00767                 // Set the new version
00768                 LLViewerImage* image = gImageList.getImage( texture_ctrl->getImageAssetID() );
00769                 if( image->getID().isNull() )
00770                 {
00771                         image = gImageList.getImage(IMG_DEFAULT_AVATAR);
00772                 }
00773                 avatar->setLocTexTE( te, image, TRUE );
00774                 gAgent.sendAgentSetAppearance();
00775         }
00776 }
00777 
00778 
00779 ESubpart LLPanelEditWearable::getDefaultSubpart()
00780 {
00781         switch( mType )
00782         {
00783                 case WT_SHAPE:          return SUBPART_SHAPE_WHOLE;
00784                 case WT_SKIN:           return SUBPART_SKIN_COLOR;
00785                 case WT_HAIR:           return SUBPART_HAIR_COLOR;
00786                 case WT_EYES:           return SUBPART_EYES;
00787                 case WT_SHIRT:          return SUBPART_SHIRT;
00788                 case WT_PANTS:          return SUBPART_PANTS;
00789                 case WT_SHOES:          return SUBPART_SHOES;
00790                 case WT_SOCKS:          return SUBPART_SOCKS;
00791                 case WT_JACKET:         return SUBPART_JACKET;
00792                 case WT_GLOVES:         return SUBPART_GLOVES;
00793                 case WT_UNDERSHIRT:     return SUBPART_UNDERSHIRT;
00794                 case WT_UNDERPANTS:     return SUBPART_UNDERPANTS;
00795                 case WT_SKIRT:          return SUBPART_SKIRT;
00796 
00797                 default:        llassert(0);            return SUBPART_SHAPE_WHOLE;
00798         }
00799 }
00800 
00801 
00802 void LLPanelEditWearable::draw()
00803 {
00804         if( gFloaterCustomize->isMinimized() )
00805         {
00806                 return;
00807         }
00808 
00809         LLVOAvatar* avatar = gAgent.getAvatarObject();
00810         if( !avatar )
00811         {
00812                 return;
00813         }
00814 
00815         if( gFloaterCustomize->isFrontmost() && !gFocusMgr.getKeyboardFocus() )
00816         {
00817                 // Route menu to this class
00818                 gEditMenuHandler = this;
00819         }
00820 
00821         LLWearable* wearable = gAgent.getWearable( mType );
00822         BOOL has_wearable = (wearable != NULL );
00823         BOOL is_dirty = isDirty();
00824         BOOL is_modifiable = FALSE;
00825         BOOL is_copyable = FALSE;
00826         BOOL is_complete = FALSE;
00827         LLViewerInventoryItem* item;
00828         item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(mType);
00829         if(item)
00830         {
00831                 const LLPermissions& perm = item->getPermissions();
00832                 is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
00833                 is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID());
00834                 is_complete = item->isComplete();
00835         }
00836 
00837         childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty);
00838         childSetEnabled("Save As", is_copyable && is_complete && has_wearable);
00839         childSetEnabled("Revert", has_wearable && is_dirty );
00840         childSetEnabled("Take Off",  has_wearable );
00841         childSetVisible("Take Off", mCanTakeOff  );
00842         childSetVisible("Create New", !has_wearable );
00843 
00844         childSetVisible("not worn instructions",  !has_wearable );
00845         childSetVisible("no modify instructions",  has_wearable && !is_modifiable);
00846 
00847         for (std::map<ESubpart, LLSubpart*>::iterator iter = mSubpartList.begin();
00848                  iter != mSubpartList.end(); ++iter)
00849         {
00850                 if( has_wearable && is_complete && is_modifiable )
00851                 {
00852                         childSetEnabled(iter->second->mButtonName, iter->second->mSex & avatar->getSex() );
00853                 }
00854                 else
00855                 {
00856                         childSetEnabled(iter->second->mButtonName, FALSE );
00857                 }
00858         }
00859 
00860         childSetVisible("square", !is_modifiable);
00861 
00862         childSetVisible("title", FALSE);
00863         childSetVisible("title_no_modify", FALSE);
00864         childSetVisible("title_not_worn", FALSE);
00865         childSetVisible("title_loading", FALSE);
00866 
00867         childSetVisible("path", FALSE);
00868         
00869         if(has_wearable && !is_modifiable)
00870         {
00871                 // *TODO:Translate
00872                 childSetVisible("title_no_modify", TRUE);
00873                 childSetTextArg("title_no_modify", "[DESC]", LLString(LLWearable::typeToTypeLabel( mType )));
00874                 
00875                 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
00876                          iter != mTextureList.end(); ++iter )
00877                 {
00878                         childSetVisible(iter->first, FALSE );
00879                 }
00880                 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
00881                          iter != mColorList.end(); ++iter )
00882                 {
00883                         childSetVisible(iter->first, FALSE );
00884                 }
00885         }
00886         else if(has_wearable && !is_complete)
00887         {
00888                 // *TODO:Translate
00889                 childSetVisible("title_loading", TRUE);
00890                 childSetTextArg("title_loading", "[DESC]", LLString(LLWearable::typeToTypeLabel( mType )));
00891                         
00892                 LLString path;
00893                 const LLUUID& item_id = gAgent.getWearableItem( wearable->getType() );
00894                 gInventory.appendPath(item_id, path);
00895                 childSetVisible("path", TRUE);
00896                 childSetTextArg("path", "[PATH]", path);
00897 
00898                 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
00899                          iter != mTextureList.end(); ++iter )
00900                 {
00901                         childSetVisible(iter->first, FALSE );
00902                 }
00903                 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
00904                          iter != mColorList.end(); ++iter )
00905                 {
00906                         childSetVisible(iter->first, FALSE );
00907                 }
00908         }
00909         else if(has_wearable && is_modifiable)
00910         {
00911                 childSetVisible("title", TRUE);
00912                 childSetTextArg("title", "[DESC]", wearable->getName() );
00913 
00914                 LLString path;
00915                 const LLUUID& item_id = gAgent.getWearableItem( wearable->getType() );
00916                 gInventory.appendPath(item_id, path);
00917                 childSetVisible("path", TRUE);
00918                 childSetTextArg("path", "[PATH]", path);
00919 
00920                 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
00921                          iter != mTextureList.end(); ++iter )
00922                 {
00923                         LLString name = iter->first;
00924                         LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>(name);
00925                         S32 te_index = iter->second;
00926                         childSetVisible(name, is_copyable && is_modifiable && is_complete );
00927                         if (texture_ctrl)
00928                         {
00929                                 const LLTextureEntry* te = avatar->getTE(te_index);
00930                                 if( te && (te->getID() != IMG_DEFAULT_AVATAR) )
00931                                 {
00932                                         texture_ctrl->setImageAssetID( te->getID() );
00933                                 }
00934                                 else
00935                                 {
00936                                         texture_ctrl->setImageAssetID( LLUUID::null );
00937                                 }
00938                         }
00939                 }
00940 
00941                 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
00942                          iter != mColorList.end(); ++iter )
00943                 {
00944                         LLString name = iter->first;
00945                         S32 te_index = iter->second;
00946                         childSetVisible(name, is_modifiable && is_complete );
00947                         childSetEnabled(name, is_modifiable && is_complete );
00948                         LLColorSwatchCtrl* ctrl = getChild<LLColorSwatchCtrl>(name);
00949                         if (ctrl)
00950                         {
00951                                 ctrl->set(avatar->getClothesColor( (LLVOAvatar::ETextureIndex)te_index ) );
00952                         }
00953                 }
00954         }
00955         else
00956         {
00957                 // *TODO:Translate
00958                 childSetVisible("title_not_worn", TRUE);
00959                 childSetTextArg("title_not_worn", "[DESC]", LLString(LLWearable::typeToTypeLabel( mType )));
00960 
00961                 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
00962                          iter != mTextureList.end(); ++iter )
00963                 {
00964                         childSetVisible(iter->first, FALSE );
00965                 }
00966                 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
00967                          iter != mColorList.end(); ++iter )
00968                 {
00969                         childSetVisible(iter->first, FALSE );
00970                 }
00971         }
00972         
00973         childSetVisible("icon", has_wearable && is_modifiable);
00974 
00975         LLPanel::draw();
00976 }
00977 
00978 void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete)
00979 {
00980         if( wearable )
00981         {
00982                 setUIPermissions(perm_mask, is_complete);
00983         }
00984         mUndoBuffer->flushActions();
00985 }
00986 
00987 void LLPanelEditWearable::addVisualParamToUndoBuffer( S32 param_id, F32 current_weight )
00988 {
00989         LLUndoWearable* action = (LLUndoWearable*)(mUndoBuffer->getNextAction());
00990         action->setVisualParam( param_id, current_weight );
00991 }
00992 
00993 void LLPanelEditWearable::switchToDefaultSubpart()
00994 {
00995         setSubpart( getDefaultSubpart() );
00996 }
00997 
00998 void LLPanelEditWearable::setVisible(BOOL visible)
00999 {
01000         LLPanel::setVisible( visible );
01001         if( !visible )
01002         {
01003                 // Route menu back to the default
01004                 if( gEditMenuHandler == this )
01005                 {
01006                         gEditMenuHandler = NULL;
01007                 }
01008 
01009                 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
01010                          iter != mColorList.end(); ++iter )
01011                 {
01012                         // this forces any open color pickers to cancel their selection
01013                         childSetEnabled(iter->first, FALSE );
01014                 }
01015         }
01016 }
01017 
01018 BOOL LLPanelEditWearable::isDirty() const
01019 {
01020         LLWearable* wearable = gAgent.getWearable( mType );
01021         if( !wearable )
01022         {
01023                 return FALSE;
01024         }
01025 
01026         if( wearable->isDirty() )
01027         {
01028                 return TRUE;
01029         }
01030 
01031         return FALSE;
01032 }
01033 
01034 // static
01035 void LLPanelEditWearable::onCommitSexChange( LLUICtrl*, void* userdata )
01036 {
01037         LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
01038 
01039         LLVOAvatar* avatar = gAgent.getAvatarObject();
01040         if (!avatar)
01041         {
01042                 return;
01043         }
01044 
01045         if( !gAgent.isWearableModifiable(self->mType))
01046         {
01047                 return;
01048         }
01049 
01050         ESex new_sex = gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE;
01051 
01052         LLViewerVisualParam* param = (LLViewerVisualParam*)avatar->getVisualParam( "male" );
01053         if( !param )
01054         {
01055                 return;
01056         }
01057 
01058         self->addVisualParamToUndoBuffer( param->getID(), param->getWeight() ); 
01059         param->setWeight( (new_sex == SEX_MALE), TRUE );
01060 
01061         avatar->updateSexDependentLayerSets( TRUE );
01062 
01063         avatar->updateVisualParams();
01064 
01065         gFloaterCustomize->clearScrollingPanelList();
01066 
01067         // Assumes that we're in the "Shape" Panel.
01068         self->setSubpart( SUBPART_SHAPE_WHOLE );
01069 
01070         gAgent.sendAgentSetAppearance();
01071 }
01072 
01073 void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete)
01074 {
01075         BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE;
01076         BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE;
01077 
01078         childSetEnabled("Save", is_modifiable && is_complete);
01079         childSetEnabled("Save As", is_copyable && is_complete);
01080         childSetEnabled("Randomize", is_modifiable && is_complete);
01081         childSetEnabled("sex radio", is_modifiable && is_complete);
01082         for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
01083                  iter != mTextureList.end(); ++iter )
01084         {
01085                 childSetVisible(iter->first, is_copyable && is_modifiable && is_complete );
01086         }
01087         for( std::map<LLString, S32>::iterator iter = mColorList.begin();
01088                  iter != mColorList.end(); ++iter )
01089         {
01090                 childSetVisible(iter->first, is_modifiable && is_complete );
01091         }
01092 }
01093 
01095 // LLScrollingPanelParam
01096 
01097 class LLScrollingPanelParam : public LLScrollingPanel
01098 {
01099 public:
01100         LLScrollingPanelParam( const LLString& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify );
01101         virtual ~LLScrollingPanelParam();
01102 
01103         virtual void            draw();
01104         virtual void            setVisible( BOOL visible );
01105         virtual void            updatePanel(BOOL allow_modify);
01106 
01107         static void                     onSliderMouseDown(LLUICtrl* ctrl, void* userdata);
01108         static void                     onSliderMoved(LLUICtrl* ctrl, void* userdata);
01109         static void                     onSliderMouseUp(LLUICtrl* ctrl, void* userdata);
01110 
01111         static void                     onHintMinMouseDown(void* userdata);
01112         static void                     onHintMinHeldDown(void* userdata);
01113         static void                     onHintMaxMouseDown(void* userdata);
01114         static void                     onHintMaxHeldDown(void* userdata);
01115         static void                     onHintMinMouseUp(void* userdata);
01116         static void                     onHintMaxMouseUp(void* userdata);
01117 
01118         void                            onHintMouseDown( LLVisualParamHint* hint );
01119         void                            onHintHeldDown( LLVisualParamHint* hint );
01120 
01121         F32                                     weightToPercent( F32 weight );
01122         F32                                     percentToWeight( F32 percent );
01123 
01124 public:
01125         LLViewerVisualParam* mParam;
01126         LLVisualParamHint*      mHintMin;
01127         LLVisualParamHint*      mHintMax;
01128         static S32                      sUpdateDelayFrames;
01129         
01130 protected:
01131         LLTimer                         mMouseDownTimer;        // timer for how long mouse has been held down on a hint.
01132         F32                                     mLastHeldTime;
01133 
01134         BOOL mAllowModify;
01135 };
01136 
01137 //static
01138 S32 LLScrollingPanelParam::sUpdateDelayFrames = 0;
01139 
01140 const S32 BTN_BORDER = 2;
01141 const S32 PARAM_HINT_WIDTH = 128;
01142 const S32 PARAM_HINT_HEIGHT = 128;
01143 const S32 PARAM_HINT_LABEL_HEIGHT = 16;
01144 const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + PARAM_HINT_WIDTH +  LLPANEL_BORDER_WIDTH);
01145 const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; 
01146 
01147 LLScrollingPanelParam::LLScrollingPanelParam( const LLString& name,
01148                                                                                           LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify )
01149         : LLScrollingPanel( name, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 ) ),
01150           mParam(param),
01151           mAllowModify(allow_modify)
01152 {
01153         LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml");
01154 
01155         S32 pos_x = 2 * LLPANEL_BORDER_WIDTH;
01156         S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT;
01157         F32 min_weight = param->getMinWeight();
01158         F32 max_weight = param->getMaxWeight();
01159 
01160         mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param,  min_weight);
01161         pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER;
01162         mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight );
01163         
01164         mHintMin->setAllowsUpdates( FALSE );
01165         mHintMax->setAllowsUpdates( FALSE );
01166         childSetValue("param slider", weightToPercent(param->getWeight()));
01167         childSetLabelArg("param slider", "[DESC]", param->getDisplayName());
01168         childSetEnabled("param slider", mAllowModify);
01169         childSetCommitCallback("param slider", LLScrollingPanelParam::onSliderMoved, this);
01170 
01171         // *TODO::translate
01172         LLString min_name = param->getMinDisplayName();
01173         LLString max_name = param->getMaxDisplayName();
01174         childSetValue("min param text", min_name);
01175         childSetValue("max param text", max_name);
01176 
01177         LLButton* less = getChild<LLButton>("less");
01178         if (less)
01179         {
01180                 less->setMouseDownCallback( LLScrollingPanelParam::onHintMinMouseDown );
01181                 less->setMouseUpCallback( LLScrollingPanelParam::onHintMinMouseUp );
01182                 less->setHeldDownCallback( LLScrollingPanelParam::onHintMinHeldDown );
01183                 less->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD );
01184         }
01185 
01186         LLButton* more = getChild<LLButton>("more");
01187         if (more)
01188         {
01189                 more->setMouseDownCallback( LLScrollingPanelParam::onHintMaxMouseDown );
01190                 more->setMouseUpCallback( LLScrollingPanelParam::onHintMaxMouseUp );
01191                 more->setHeldDownCallback( LLScrollingPanelParam::onHintMaxHeldDown );
01192                 more->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD );
01193         }
01194 
01195         setVisible(FALSE);
01196         setBorderVisible( FALSE );
01197 }
01198 
01199 LLScrollingPanelParam::~LLScrollingPanelParam()
01200 {
01201         delete mHintMin;
01202         delete mHintMax;
01203 }
01204 
01205 void LLScrollingPanelParam::updatePanel(BOOL allow_modify)
01206 {
01207         LLViewerVisualParam* param = mHintMin->getVisualParam();
01208         childSetValue("param slider", weightToPercent( param->getWeight() ) );
01209         mHintMin->requestUpdate( sUpdateDelayFrames++ );
01210         mHintMax->requestUpdate( sUpdateDelayFrames++ );
01211 
01212         mAllowModify = allow_modify;
01213         childSetEnabled("param slider", mAllowModify);
01214         childSetEnabled("less", mAllowModify);
01215         childSetEnabled("more", mAllowModify);
01216 }
01217 
01218 void LLScrollingPanelParam::setVisible( BOOL visible )
01219 {
01220         if( getVisible() != visible )
01221         {
01222                 LLPanel::setVisible( visible );
01223                 mHintMin->setAllowsUpdates( visible );
01224                 mHintMax->setAllowsUpdates( visible );
01225 
01226                 if( visible )
01227                 {
01228                         mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ );
01229                         mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ );
01230                 }
01231         }
01232 }
01233 
01234 void LLScrollingPanelParam::draw()
01235 {
01236         if( gFloaterCustomize->isMinimized() )
01237         {
01238                 return;
01239         }
01240         
01241         childSetVisible("less", mHintMin->getVisible());
01242         childSetVisible("more", mHintMax->getVisible());
01243 
01244         // Draw all the children except for the labels
01245         childSetVisible( "min param text", FALSE );
01246         childSetVisible( "max param text", FALSE );
01247         LLPanel::draw();
01248 
01249         // Draw the hints over the "less" and "more" buttons.
01250         glPushMatrix();
01251         {
01252                 const LLRect& r = mHintMin->getRect();
01253                 F32 left = (F32)(r.mLeft + BTN_BORDER);
01254                 F32 bot  = (F32)(r.mBottom + BTN_BORDER);
01255                 glTranslatef(left, bot, 0.f);
01256                 mHintMin->draw();
01257         }
01258         glPopMatrix();
01259 
01260         glPushMatrix();
01261         {
01262                 const LLRect& r = mHintMax->getRect();
01263                 F32 left = (F32)(r.mLeft + BTN_BORDER);
01264                 F32 bot  = (F32)(r.mBottom + BTN_BORDER);
01265                 glTranslatef(left, bot, 0.f);
01266                 mHintMax->draw();
01267         }
01268         glPopMatrix();
01269 
01270 
01271         // Draw labels on top of the buttons
01272         childSetVisible( "min param text", TRUE );
01273         drawChild(getChild<LLView>("min param text"), BTN_BORDER, BTN_BORDER);
01274 
01275         childSetVisible( "max param text", TRUE );
01276         drawChild(getChild<LLView>("max param text"), BTN_BORDER, BTN_BORDER);
01277 }
01278 
01279 // static
01280 void LLScrollingPanelParam::onSliderMoved(LLUICtrl* ctrl, void* userdata)
01281 {
01282         LLSliderCtrl* slider = (LLSliderCtrl*) ctrl;
01283         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01284         LLViewerVisualParam* param = self->mParam;
01285 
01286         F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( param );
01287         F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() );
01288         if (current_weight != new_weight )
01289         {
01290                 gAgent.getAvatarObject()->setVisualParamWeight( param, new_weight, TRUE);
01291                 gAgent.getAvatarObject()->updateVisualParams();
01292         }
01293 }
01294 
01295 // static
01296 void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata)
01297 {
01298         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01299         LLViewerVisualParam* param = self->mParam;
01300 
01301         // store existing values in undo buffer
01302         F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( param );
01303 
01304         if( gFloaterCustomize )
01305         {
01306                 LLPanelEditWearable* panel = gFloaterCustomize->getCurrentWearablePanel();
01307                 if( panel )
01308                 {
01309                         panel->addVisualParamToUndoBuffer( param->getID(), current_weight ); 
01310                 }
01311         }
01312 }
01313 
01314 // static
01315 void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata)
01316 {
01317         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01318 
01319         // store namevalue
01320         gAgent.sendAgentSetAppearance();
01321 
01322         LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax );
01323 }
01324 
01325 // static
01326 void LLScrollingPanelParam::onHintMinMouseDown( void* userdata )
01327 {
01328         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01329         self->onHintMouseDown( self->mHintMin );
01330 }
01331 
01332 // static
01333 void LLScrollingPanelParam::onHintMaxMouseDown( void* userdata )
01334 {
01335         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01336         self->onHintMouseDown( self->mHintMax );
01337 }
01338 
01339 
01340 void LLScrollingPanelParam::onHintMouseDown( LLVisualParamHint* hint )
01341 {
01342         // morph towards this result
01343         F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( hint->getVisualParam() );
01344 
01345         // if we have maxed out on this morph, we shouldn't be able to click it
01346         if( hint->getVisualParamWeight() != current_weight )
01347         {
01348                 // store existing values in undo buffer
01349                 if( gFloaterCustomize )
01350                 {
01351                         LLPanelEditWearable* panel = gFloaterCustomize->getCurrentWearablePanel();
01352                         if( panel )
01353                         {
01354                                 panel->addVisualParamToUndoBuffer( hint->getVisualParam()->getID(), current_weight ); 
01355                         }
01356                 }
01357 
01358                 mMouseDownTimer.reset();
01359                 mLastHeldTime = 0.f;
01360         }
01361 }
01362 
01363 // static
01364 void LLScrollingPanelParam::onHintMinHeldDown( void* userdata )
01365 {
01366         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01367         self->onHintHeldDown( self->mHintMin );
01368 }
01369 
01370 // static
01371 void LLScrollingPanelParam::onHintMaxHeldDown( void* userdata )
01372 {
01373         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01374         self->onHintHeldDown( self->mHintMax );
01375 }
01376         
01377 void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint )
01378 {
01379         F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( hint->getVisualParam() );
01380 
01381         if (current_weight != hint->getVisualParamWeight() )
01382         {
01383                 const F32 FULL_BLEND_TIME = 2.f;
01384                 F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime;
01385                 mLastHeldTime += elapsed_time;
01386 
01387                 F32 new_weight;
01388                 if (current_weight > hint->getVisualParamWeight() )
01389                 {
01390                         new_weight = current_weight - (elapsed_time / FULL_BLEND_TIME);
01391                 }
01392                 else
01393                 {
01394                         new_weight = current_weight + (elapsed_time / FULL_BLEND_TIME);
01395                 }
01396 
01397                 // Make sure we're not taking the slider out of bounds
01398                 // (this is where some simple UI limits are stored)
01399                 F32 new_percent = weightToPercent(new_weight);
01400                 LLSliderCtrl* slider = getChild<LLSliderCtrl>("param slider");
01401                 if (slider)
01402                 {
01403                         if (slider->getMinValue() < new_percent
01404                                 && new_percent < slider->getMaxValue())
01405                         {
01406                                 gAgent.getAvatarObject()->setVisualParamWeight( hint->getVisualParam(), new_weight, TRUE);
01407                                 gAgent.getAvatarObject()->updateVisualParams();
01408 
01409                                 slider->setValue( weightToPercent( new_weight ) );
01410                         }
01411                 }
01412         }
01413 }
01414 
01415 // static
01416 void LLScrollingPanelParam::onHintMinMouseUp( void* userdata )
01417 {
01418         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01419 
01420         F32 elapsed_time = self->mMouseDownTimer.getElapsedTimeF32();
01421 
01422         LLVOAvatar* avatar = gAgent.getAvatarObject();
01423         if (avatar)
01424         {
01425                 LLVisualParamHint* hint = self->mHintMin;
01426 
01427                 if (elapsed_time < PARAM_STEP_TIME_THRESHOLD)
01428                 {
01429                         // step in direction
01430                         F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( hint->getVisualParam() );
01431                         F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight();
01432                         // step a fraction in the negative directiona
01433                         F32 new_weight = current_weight - (range / 10.f);
01434                         F32 new_percent = self->weightToPercent(new_weight);
01435                         LLSliderCtrl* slider = self->getChild<LLSliderCtrl>("param slider");
01436                         if (slider)
01437                         {
01438                                 if (slider->getMinValue() < new_percent
01439                                         && new_percent < slider->getMaxValue())
01440                                 {
01441                                         avatar->setVisualParamWeight(hint->getVisualParam(), new_weight, TRUE);
01442                                         slider->setValue( self->weightToPercent( new_weight ) );
01443                                 }
01444                         }
01445                 }
01446 
01447                 // store namevalue
01448                 gAgent.sendAgentSetAppearance();
01449         }
01450 
01451         LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax );
01452 }
01453 
01454 void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata )
01455 {
01456         LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
01457 
01458         F32 elapsed_time = self->mMouseDownTimer.getElapsedTimeF32();
01459 
01460         LLVOAvatar* avatar = gAgent.getAvatarObject();
01461         if (avatar)
01462         {
01463                 LLVisualParamHint* hint = self->mHintMax;
01464 
01465                 if (elapsed_time < PARAM_STEP_TIME_THRESHOLD)
01466                 {
01467                         // step in direction
01468                         F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( hint->getVisualParam() );
01469                         F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight();
01470                         // step a fraction in the negative direction
01471                         F32 new_weight = current_weight + (range / 10.f);
01472                         F32 new_percent = self->weightToPercent(new_weight);
01473                         LLSliderCtrl* slider = self->getChild<LLSliderCtrl>("param slider");
01474                         if (slider)
01475                         {
01476                                 if (slider->getMinValue() < new_percent
01477                                         && new_percent < slider->getMaxValue())
01478                                 {
01479                                         avatar->setVisualParamWeight(hint->getVisualParam(), new_weight, TRUE);
01480                                         slider->setValue( self->weightToPercent( new_weight ) );
01481                                 }
01482                         }
01483                 }
01484 
01485                 // store namevalue
01486                 gAgent.sendAgentSetAppearance();
01487         }
01488 
01489         LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax );
01490 }
01491 
01492 
01493 F32 LLScrollingPanelParam::weightToPercent( F32 weight )
01494 {
01495         LLViewerVisualParam* param = mParam;
01496         return (weight - param->getMinWeight()) /  (param->getMaxWeight() - param->getMinWeight()) * 100.f;
01497 }
01498 
01499 F32 LLScrollingPanelParam::percentToWeight( F32 percent )
01500 {
01501         LLViewerVisualParam* param = mParam;
01502         return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight();
01503 }
01504 
01505 const LLString& LLFloaterCustomize::getEditGroup()
01506 {
01507         return getCurrentWearablePanel()->getCurrentSubpart()->mEditGroup;
01508 }
01509 
01510 
01512 // LLFloaterCustomize
01513 
01514 // statics
01515 EWearableType   LLFloaterCustomize::sCurrentWearableType = WT_SHAPE;
01516 
01517 struct WearablePanelData
01518 {
01519         WearablePanelData(LLFloaterCustomize* floater, EWearableType type)
01520                 : mFloater(floater), mType(type) {}
01521         LLFloaterCustomize* mFloater;
01522         EWearableType mType;
01523 };
01524 
01525 LLFloaterCustomize::LLFloaterCustomize()
01526 :       LLFloater("customize"),
01527         mScrollingPanelList( NULL ),
01528         mGenePool( NULL ),
01529         mInventoryObserver(NULL),
01530         mNextStepAfterSaveAllCallback( NULL ),
01531         mNextStepAfterSaveAllUserdata( NULL )
01532 {
01533         gSavedSettings.setU32("AvatarSex", (gAgent.getAvatarObject()->getSex() == SEX_MALE) );
01534 
01535         mResetParams = new LLVisualParamReset();
01536         
01537         // create the observer which will watch for matching incoming inventory
01538         mInventoryObserver = new LLFloaterCustomizeObserver(this);
01539         gInventory.addObserver(mInventoryObserver);
01540 
01541         LLCallbackMap::map_t factory_map;
01542         factory_map["Shape"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SHAPE) ) );
01543         factory_map["Skin"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SKIN) ) );
01544         factory_map["Hair"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_HAIR) ) );
01545         factory_map["Eyes"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_EYES) ) );
01546         factory_map["Shirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SHIRT) ) );
01547         factory_map["Pants"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_PANTS) ) );
01548         factory_map["Shoes"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SHOES) ) );
01549         factory_map["Socks"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SOCKS) ) );
01550         factory_map["Jacket"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_JACKET) ) );
01551         factory_map["Gloves"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_GLOVES) ) );
01552         factory_map["Undershirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_UNDERSHIRT) ) );
01553         factory_map["Underpants"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_UNDERPANTS) ) );
01554         factory_map["Skirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SKIRT) ) );
01555         
01556         LLUICtrlFactory::getInstance()->buildFloater(this, "floater_customize.xml", &factory_map);
01557         
01558 }
01559 
01560 BOOL LLFloaterCustomize::postBuild()
01561 {
01562         childSetAction("Make Outfit", LLFloaterCustomize::onBtnMakeOutfit, (void*)this);
01563         childSetAction("Save All", LLFloaterCustomize::onBtnSaveAll, (void*)this);
01564         childSetAction("Close", LLFloater::onClickClose, (void*)this);
01565 
01566         // Wearable panels
01567         initWearablePanels();
01568 
01569         // Tab container
01570         childSetTabChangeCallback("customize tab container", "Shape", onTabChanged, (void*)WT_SHAPE );
01571         childSetTabChangeCallback("customize tab container", "Skin", onTabChanged, (void*)WT_SKIN );
01572         childSetTabChangeCallback("customize tab container", "Hair", onTabChanged, (void*)WT_HAIR );
01573         childSetTabChangeCallback("customize tab container", "Eyes", onTabChanged, (void*)WT_EYES );
01574         childSetTabChangeCallback("customize tab container", "Shirt", onTabChanged, (void*)WT_SHIRT );
01575         childSetTabChangeCallback("customize tab container", "Pants", onTabChanged, (void*)WT_PANTS );
01576         childSetTabChangeCallback("customize tab container", "Shoes", onTabChanged, (void*)WT_SHOES );
01577         childSetTabChangeCallback("customize tab container", "Socks", onTabChanged, (void*)WT_SOCKS );
01578         childSetTabChangeCallback("customize tab container", "Jacket", onTabChanged, (void*)WT_JACKET );
01579         childSetTabChangeCallback("customize tab container", "Gloves", onTabChanged, (void*)WT_GLOVES );
01580         childSetTabChangeCallback("customize tab container", "Undershirt", onTabChanged, (void*)WT_UNDERSHIRT );
01581         childSetTabChangeCallback("customize tab container", "Underpants", onTabChanged, (void*)WT_UNDERPANTS );
01582         childSetTabChangeCallback("customize tab container", "Skirt", onTabChanged, (void*)WT_SKIRT );
01583 
01584         // Remove underwear panels for teens
01585         if (gAgent.isTeen())
01586         {
01587                 LLTabContainer* tab_container = getChild<LLTabContainer>("customize tab container");
01588                 if (tab_container)
01589                 {
01590                         LLPanel* panel;
01591                         panel = tab_container->getPanelByName("Undershirt");
01592                         if (panel) tab_container->removeTabPanel(panel);
01593                         panel = tab_container->getPanelByName("Underpants");
01594                         if (panel) tab_container->removeTabPanel(panel);
01595                 }
01596         }
01597         
01598         // Scrolling Panel
01599         initScrollingPanelList();
01600 
01601         childShowTab("customize tab container", "Shape", true);
01602         
01603         return TRUE;
01604 }
01605 
01607 
01608 // static
01609 void LLFloaterCustomize::setCurrentWearableType( EWearableType type )
01610 {
01611         if( LLFloaterCustomize::sCurrentWearableType != type )
01612         {
01613                 LLFloaterCustomize::sCurrentWearableType = type; 
01614 
01615                 S32 type_int = (S32)type;
01616                 if( gFloaterCustomize
01617                         && gFloaterCustomize->mWearablePanelList[type_int])
01618                 {
01619                         LLString panelname = gFloaterCustomize->mWearablePanelList[type_int]->getName();
01620                         gFloaterCustomize->childShowTab("customize tab container", panelname);
01621                         gFloaterCustomize->switchToDefaultSubpart();
01622                 }
01623         }
01624 }
01625 
01626 // static
01627 void LLFloaterCustomize::onBtnSaveAll( void* userdata )
01628 {
01629         gAgent.saveAllWearables();
01630 }
01631 
01632 
01633 // static
01634 void LLFloaterCustomize::onBtnSnapshot( void* userdata )
01635 {
01636         // Trigger noise, but not animation
01637         send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
01638 
01639         LLPointer<LLImageRaw> raw = new LLImageRaw;
01640         BOOL success = gViewerWindow->rawSnapshot(raw,
01641                                                                                           gViewerWindow->getWindowWidth(),
01642                                                                                           gViewerWindow->getWindowHeight(),
01643                                                                                           TRUE, // keep window aspect ratio
01644                                                                                           FALSE,
01645                                                                                           FALSE,        // UI in snapshot off
01646                                                                                           FALSE);       // do_rebuild off
01647         if (!success) return;
01648 
01649         LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
01650         success = jpeg_image->encode(raw, 0.0f);
01651         if(!success) return;
01652 
01653         LLString filepath("C:\\snapshot");
01654         filepath += ".jpg";
01655 
01656         success = jpeg_image->save(filepath);
01657 }
01658 
01659 // static
01660 void LLFloaterCustomize::onBtnMakeOutfit( void* userdata )
01661 {
01662         LLVOAvatar* avatar = gAgent.getAvatarObject();
01663         if(avatar)
01664         {
01665                 LLMakeOutfitDialog* dialog = new LLMakeOutfitDialog( onMakeOutfitCommit, NULL );
01666                 // LLMakeOutfitDialog deletes itself.
01667 
01668                 for( S32 i = 0; i < WT_COUNT; i++ )
01669                 {
01670                         BOOL enabled = (gAgent.getWearable( (EWearableType) i ) != NULL);
01671                         BOOL selected = (enabled && (WT_SHIRT <= i) && (i < WT_COUNT)); // only select clothing by default
01672                         if (gAgent.isTeen()
01673                                 && !edit_wearable_for_teens((EWearableType)i))
01674                         {
01675                                 dialog->setWearableToInclude( i, FALSE, FALSE );
01676                         }
01677                         else
01678                         {
01679                                 dialog->setWearableToInclude( i, enabled, selected );
01680                         }
01681                 }
01682                 dialog->startModal();
01683         }
01684 }
01685 
01686 // static
01687 void LLFloaterCustomize::onMakeOutfitCommit( LLMakeOutfitDialog* dialog, void* userdata )
01688 {
01689         LLVOAvatar* avatar = gAgent.getAvatarObject();
01690         if(avatar)
01691         {
01692                 LLDynamicArray<S32> wearables_to_include;
01693                 LLDynamicArray<S32> attachments_to_include;  // attachment points
01694 
01695                 dialog->getIncludedItems( wearables_to_include, attachments_to_include );
01696 
01697                 gAgent.makeNewOutfit( dialog->getFolderName(), wearables_to_include, attachments_to_include, dialog->getRenameClothing() );
01698         }
01699 }
01700 
01702 
01703 // static
01704 void* LLFloaterCustomize::createWearablePanel(void* userdata)
01705 {
01706         WearablePanelData* data = (WearablePanelData*)userdata;
01707         EWearableType type = data->mType;
01708         LLPanelEditWearable* panel;
01709         if ((gAgent.isTeen() && !edit_wearable_for_teens(data->mType) ))
01710         {
01711                 panel = NULL;
01712         }
01713         else
01714         {
01715                 panel = new LLPanelEditWearable( type );
01716         }
01717         data->mFloater->mWearablePanelList[type] = panel;
01718         delete data;
01719         return panel;
01720 }
01721 
01722 void LLFloaterCustomize::initWearablePanels()
01723 {
01724         LLSubpart* part;
01725         
01727         // Shape
01728         LLPanelEditWearable* panel = mWearablePanelList[ WT_SHAPE ];
01729 
01730         // body
01731         part = new LLSubpart();
01732         part->mTargetJoint = "mPelvis";
01733         part->mEditGroup = "shape_body";
01734         part->mTargetOffset.setVec(0.f, 0.f, 0.1f);
01735         part->mCameraOffset.setVec(-2.5f, 0.5f, 0.8f);
01736         panel->addSubpart( "Body", SUBPART_SHAPE_WHOLE, part );
01737 
01738         // head supparts
01739         part = new LLSubpart();
01740         part->mTargetJoint = "mHead";
01741         part->mEditGroup = "shape_head";
01742         part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
01743         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
01744         panel->addSubpart( "Head", SUBPART_SHAPE_HEAD, part );
01745 
01746         part = new LLSubpart();
01747         part->mTargetJoint = "mHead";
01748         part->mEditGroup = "shape_eyes";
01749         part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
01750         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
01751         panel->addSubpart( "Eyes", SUBPART_SHAPE_EYES, part );
01752 
01753         part = new LLSubpart();
01754         part->mTargetJoint = "mHead";
01755         part->mEditGroup = "shape_ears";
01756         part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
01757         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
01758         panel->addSubpart( "Ears", SUBPART_SHAPE_EARS, part );
01759 
01760         part = new LLSubpart();
01761         part->mTargetJoint = "mHead";
01762         part->mEditGroup = "shape_nose";
01763         part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
01764         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
01765         panel->addSubpart( "Nose", SUBPART_SHAPE_NOSE, part );
01766 
01767 
01768         part = new LLSubpart();
01769         part->mTargetJoint = "mHead";
01770         part->mEditGroup = "shape_mouth";
01771         part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
01772         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
01773         panel->addSubpart( "Mouth", SUBPART_SHAPE_MOUTH, part );
01774 
01775 
01776         part = new LLSubpart();
01777         part->mTargetJoint = "mHead";
01778         part->mEditGroup = "shape_chin";
01779         part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
01780         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
01781         panel->addSubpart( "Chin", SUBPART_SHAPE_CHIN, part );
01782 
01783         // torso
01784         part = new LLSubpart();
01785         part->mTargetJoint = "mTorso";
01786         part->mEditGroup = "shape_torso";
01787         part->mTargetOffset.setVec(0.f, 0.f, 0.3f);
01788         part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f);
01789         panel->addSubpart( "Torso", SUBPART_SHAPE_TORSO, part );
01790 
01791         // legs
01792         part = new LLSubpart();
01793         part->mTargetJoint = "mPelvis";
01794         part->mEditGroup = "shape_legs";
01795         part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
01796         part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
01797         panel->addSubpart( "Legs", SUBPART_SHAPE_LEGS, part );
01798 
01799         panel->childSetCommitCallback("sex radio", LLPanelEditWearable::onCommitSexChange, panel);
01800         panel->childSetAction("Randomize", &LLPanelEditWearable::onBtnRandomize, panel);
01801 
01803         // Skin
01804         panel = mWearablePanelList[ WT_SKIN ];
01805 
01806         part = new LLSubpart();
01807         part->mTargetJoint = "mHead";
01808         part->mEditGroup = "skin_color";
01809         part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
01810         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
01811         panel->addSubpart( "Skin Color", SUBPART_SKIN_COLOR, part );
01812 
01813         part = new LLSubpart();
01814         part->mTargetJoint = "mHead";
01815         part->mEditGroup = "skin_facedetail";
01816         part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
01817         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
01818         panel->addSubpart( "Face Detail", SUBPART_SKIN_FACEDETAIL, part );
01819 
01820         part = new LLSubpart();
01821         part->mTargetJoint = "mHead";
01822         part->mEditGroup = "skin_makeup";
01823         part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
01824         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
01825         panel->addSubpart( "Makeup", SUBPART_SKIN_MAKEUP, part );
01826 
01827         part = new LLSubpart();
01828         part->mTargetJoint = "mPelvis";
01829         part->mEditGroup = "skin_bodydetail";
01830         part->mTargetOffset.setVec(0.f, 0.f, -0.2f);
01831         part->mCameraOffset.setVec(-2.5f, 0.5f, 0.5f);
01832         panel->addSubpart( "Body Detail", SUBPART_SKIN_BODYDETAIL, part );
01833 
01834         panel->addTextureDropTarget( LLVOAvatar::TEX_HEAD_BODYPAINT,  "Head Tattoos",   LLUUID::null, TRUE );
01835         panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_BODYPAINT, "Upper Tattoos",  LLUUID::null, TRUE );
01836         panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_BODYPAINT, "Lower Tattoos",  LLUUID::null, TRUE );
01837 
01838         panel->childSetAction("Randomize", &LLPanelEditWearable::onBtnRandomize, panel);
01839 
01841         // Hair
01842         panel = mWearablePanelList[ WT_HAIR ];
01843 
01844         part = new LLSubpart();
01845         part->mTargetJoint = "mHead";
01846         part->mEditGroup = "hair_color";
01847         part->mTargetOffset.setVec(0.f, 0.f, 0.10f);
01848         part->mCameraOffset.setVec(-0.4f, 0.05f, 0.10f);
01849         panel->addSubpart( "Color", SUBPART_HAIR_COLOR, part );
01850 
01851         part = new LLSubpart();
01852         part->mTargetJoint = "mHead";
01853         part->mEditGroup = "hair_style";
01854         part->mTargetOffset.setVec(0.f, 0.f, 0.10f);
01855         part->mCameraOffset.setVec(-0.4f, 0.05f, 0.10f);
01856         panel->addSubpart( "Style", SUBPART_HAIR_STYLE, part );
01857 
01858         part = new LLSubpart();
01859         part->mTargetJoint = "mHead";
01860         part->mEditGroup = "hair_eyebrows";
01861         part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
01862         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
01863         panel->addSubpart( "Eyebrows", SUBPART_HAIR_EYEBROWS, part );
01864 
01865         part = new LLSubpart();
01866         part->mSex = SEX_MALE;
01867         part->mTargetJoint = "mHead";
01868         part->mEditGroup = "hair_facial";
01869         part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
01870         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
01871         panel->addSubpart( "Facial", SUBPART_HAIR_FACIAL, part );
01872 
01873         panel->addTextureDropTarget(LLVOAvatar::TEX_HAIR, "Texture",
01874                                                                 LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ),
01875                                                                 FALSE );
01876 
01877         panel->childSetAction("Randomize", &LLPanelEditWearable::onBtnRandomize, panel);
01878 
01880         // Eyes
01881         panel = mWearablePanelList[ WT_EYES ];
01882 
01883         part = new LLSubpart();
01884         part->mTargetJoint = "mHead";
01885         part->mEditGroup = "eyes";
01886         part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
01887         part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
01888         panel->addSubpart( "", SUBPART_EYES, part );
01889 
01890         panel->addTextureDropTarget(LLVOAvatar::TEX_EYES_IRIS, "Iris",
01891                                                                 LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ),
01892                                                                 FALSE );
01893 
01894         panel->childSetAction("Randomize", &LLPanelEditWearable::onBtnRandomize, panel);
01895 
01897         // Shirt
01898         panel = mWearablePanelList[ WT_SHIRT ];
01899 
01900         part = new LLSubpart();
01901         part->mTargetJoint = "mTorso";
01902         part->mEditGroup = "shirt";
01903         part->mTargetOffset.setVec(0.f, 0.f, 0.3f);
01904         part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f);
01905         panel->addSubpart( "", SUBPART_SHIRT, part );
01906 
01907         panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_SHIRT, "Fabric",
01908                                                                  LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ),
01909                                                                  FALSE );
01910 
01911         panel->addColorSwatch( LLVOAvatar::TEX_UPPER_SHIRT, "Color/Tint" );
01912 
01913 
01915         // Pants
01916         panel = mWearablePanelList[ WT_PANTS ];
01917 
01918         part = new LLSubpart();
01919         part->mTargetJoint = "mPelvis";
01920         part->mEditGroup = "pants";
01921         part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
01922         part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
01923         panel->addSubpart( "", SUBPART_PANTS, part );
01924 
01925         panel->addTextureDropTarget(LLVOAvatar::TEX_LOWER_PANTS, "Fabric",
01926                                                                 LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ),
01927                                                                 FALSE );
01928 
01929         panel->addColorSwatch( LLVOAvatar::TEX_LOWER_PANTS, "Color/Tint" );
01930 
01931 
01933         // Shoes
01934         panel = mWearablePanelList[ WT_SHOES ];
01935 
01936         if (panel)
01937         {
01938                 part = new LLSubpart();
01939                 part->mTargetJoint = "mPelvis";
01940                 part->mEditGroup = "shoes";
01941                 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
01942                 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
01943                 panel->addSubpart( "", SUBPART_SHOES, part );
01944 
01945                 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_SHOES, "Fabric",
01946                                                                          LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ),
01947                                                                          FALSE );
01948 
01949                 panel->addColorSwatch( LLVOAvatar::TEX_LOWER_SHOES, "Color/Tint" );
01950         }
01951 
01952 
01954         // Socks
01955         panel = mWearablePanelList[ WT_SOCKS ];
01956 
01957         if (panel)
01958         {
01959                 part = new LLSubpart();
01960                 part->mTargetJoint = "mPelvis";
01961                 part->mEditGroup = "socks";
01962                 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
01963                 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
01964                 panel->addSubpart( "", SUBPART_SOCKS, part );
01965 
01966                 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_SOCKS, "Fabric",
01967                                                                          LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ),
01968                                                                          FALSE );
01969 
01970                 panel->addColorSwatch( LLVOAvatar::TEX_LOWER_SOCKS, "Color/Tint" );
01971         }
01972 
01974         // Jacket
01975         panel = mWearablePanelList[ WT_JACKET ];
01976 
01977         if (panel)
01978         {
01979                 part = new LLSubpart();
01980                 part->mTargetJoint = "mTorso";
01981                 part->mEditGroup = "jacket";
01982                 part->mTargetOffset.setVec(0.f, 0.f, 0.f);
01983                 part->mCameraOffset.setVec(-2.f, 0.1f, 0.3f);
01984                 panel->addSubpart( "", SUBPART_JACKET, part );
01985 
01986                 panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_JACKET, "Upper Fabric",
01987                                                                          LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ),
01988                                                                          FALSE );
01989                 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_JACKET, "Lower Fabric",
01990                                                                          LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ),
01991                                                                          FALSE );
01992 
01993                 panel->addColorSwatch( LLVOAvatar::TEX_UPPER_JACKET, "Color/Tint" );
01994         }
01995 
01997         // Skirt
01998         panel = mWearablePanelList[ WT_SKIRT ];
01999 
02000         if (panel)
02001         {
02002                 part = new LLSubpart();
02003                 part->mTargetJoint = "mPelvis";
02004                 part->mEditGroup = "skirt";
02005                 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
02006                 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
02007                 panel->addSubpart( "", SUBPART_SKIRT, part );
02008 
02009                 panel->addTextureDropTarget( LLVOAvatar::TEX_SKIRT,  "Fabric",
02010                                                                          LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ),
02011                                                                          FALSE );
02012 
02013                 panel->addColorSwatch( LLVOAvatar::TEX_SKIRT, "Color/Tint" );
02014         }
02015 
02016 
02018         // Gloves
02019         panel = mWearablePanelList[ WT_GLOVES ];
02020 
02021         if (panel)
02022         {
02023                 part = new LLSubpart();
02024                 part->mTargetJoint = "mTorso";
02025                 part->mEditGroup = "gloves";
02026                 part->mTargetOffset.setVec(0.f, 0.f, 0.f);
02027                 part->mCameraOffset.setVec(-1.f, 0.15f, 0.f);
02028                 panel->addSubpart( "", SUBPART_GLOVES, part );
02029 
02030                 panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_GLOVES,  "Fabric",
02031                                                                          LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ),
02032                                                                          FALSE );
02033 
02034                 panel->addColorSwatch( LLVOAvatar::TEX_UPPER_GLOVES, "Color/Tint" );
02035         }
02036 
02037 
02039         // Undershirt
02040         panel = mWearablePanelList[ WT_UNDERSHIRT ];
02041 
02042         if (panel)
02043         {
02044                 part = new LLSubpart();
02045                 part->mTargetJoint = "mTorso";
02046                 part->mEditGroup = "undershirt";
02047                 part->mTargetOffset.setVec(0.f, 0.f, 0.3f);
02048                 part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f);
02049                 panel->addSubpart( "", SUBPART_UNDERSHIRT, part );
02050 
02051                 panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_UNDERSHIRT,  "Fabric",
02052                                                                          LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ),
02053                                                                          FALSE );
02054 
02055                 panel->addColorSwatch( LLVOAvatar::TEX_UPPER_UNDERSHIRT, "Color/Tint" );
02056         }
02057 
02059         // Underpants
02060         panel = mWearablePanelList[ WT_UNDERPANTS ];
02061 
02062         if (panel)
02063         {
02064                 part = new LLSubpart();
02065                 part->mTargetJoint = "mPelvis";
02066                 part->mEditGroup = "underpants";
02067                 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
02068                 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
02069                 panel->addSubpart( "", SUBPART_UNDERPANTS, part );
02070 
02071                 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_UNDERPANTS, "Fabric",
02072                                                                          LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ),
02073                                                                          FALSE );
02074 
02075                 panel->addColorSwatch( LLVOAvatar::TEX_LOWER_UNDERPANTS, "Color/Tint" );
02076         }
02077 }
02078 
02080 
02081 LLFloaterCustomize::~LLFloaterCustomize()
02082 {
02083         llinfos << "Destroying LLFloaterCustomize" << llendl;
02084         delete mGenePool;
02085         delete mResetParams;
02086         gInventory.removeObserver(mInventoryObserver);
02087         delete mInventoryObserver;
02088 }
02089 
02090 void LLFloaterCustomize::switchToDefaultSubpart()
02091 {
02092         getCurrentWearablePanel()->switchToDefaultSubpart();
02093 }
02094 
02095 void LLFloaterCustomize::spawnWearableAppearance(EWearableType type)
02096 {
02097         if( !mGenePool )
02098         {
02099                 mGenePool = new LLGenePool();
02100         }
02101 
02102         LLVOAvatar* avatar = gAgent.getAvatarObject();
02103         if( avatar )
02104         {
02105                 mGenePool->spawn( type );
02106         }
02107 }
02108 
02109 
02110 void LLFloaterCustomize::draw()
02111 {
02112         if( isMinimized() )
02113         {
02114                 LLFloater::draw();
02115                 return;
02116         }
02117 
02118         // only do this if we are in the customize avatar mode
02119         // and not transitioning into or out of it
02120         // *TODO: This is a sort of expensive call, which only needs
02121         // to be called when the tabs change or an inventory item
02122         // arrives. Figure out some way to avoid this if possible.
02123         updateInventoryUI();
02124 
02125         LLScrollingPanelParam::sUpdateDelayFrames = 0;
02126         
02127         childSetEnabled("Save All",  isDirty() );
02128         LLFloater::draw();
02129 }
02130 
02131 BOOL LLFloaterCustomize::isDirty() const
02132 {
02133         for(S32 i = 0; i < WT_COUNT; i++)
02134         {
02135                 if( mWearablePanelList[i]
02136                         && mWearablePanelList[i]->isDirty() )
02137                 {
02138                         return TRUE;
02139                 }
02140         }
02141         return FALSE;
02142 }
02143 
02144 
02145 // static
02146 void LLFloaterCustomize::onTabChanged( void* userdata, bool from_click )
02147 {
02148         EWearableType wearable_type = (EWearableType) (intptr_t)userdata;
02149         LLFloaterCustomize::setCurrentWearableType( wearable_type );
02150 }
02151 
02152 void LLFloaterCustomize::onClose(bool app_quitting)
02153 {
02154         // since this window is potentially staying open, push to back to let next window take focus
02155         gFloaterView->sendChildToBack(this);
02156         handle_reset_view();  // Calls askToSaveAllIfDirty
02157 }
02158 
02159 
02161 
02162 const S32 LOWER_BTN_HEIGHT = 18 + 8;
02163 
02164 const S32 FLOATER_CUSTOMIZE_BUTTON_WIDTH = 82;
02165 const S32 FLOATER_CUSTOMIZE_BOTTOM_PAD = 30;
02166 const S32 LINE_HEIGHT = 16;
02167 const S32 HEADER_PAD = 8;
02168 const S32 HEADER_HEIGHT = 3 * (LINE_HEIGHT + LLFLOATER_VPAD) + (2 * LLPANEL_BORDER_WIDTH) + HEADER_PAD; 
02169 
02170 void LLFloaterCustomize::initScrollingPanelList()
02171 {
02172         LLScrollableContainerView* scroll_container =
02173                 getChild<LLScrollableContainerView>("panel_container");
02174         // LLScrollingPanelList's do not import correctly 
02175 //      mScrollingPanelList = LLUICtrlFactory::getScrollingPanelList(this, "panel_list");
02176         mScrollingPanelList = new LLScrollingPanelList("panel_list", LLRect());
02177         if (scroll_container)
02178         {
02179                 scroll_container->setScrolledView(mScrollingPanelList);
02180                 scroll_container->addChild(mScrollingPanelList);
02181         }
02182 }
02183 
02184 void LLFloaterCustomize::clearScrollingPanelList()
02185 {
02186         if( mScrollingPanelList )
02187         {
02188                 mScrollingPanelList->clearPanels();
02189         }
02190 }
02191 
02192 void LLFloaterCustomize::generateVisualParamHints(LLViewerJointMesh* joint_mesh, LLFloaterCustomize::param_map& params)
02193 {
02194         // sorted_params is sorted according to magnitude of effect from
02195         // least to greatest.  Adding to the front of the child list
02196         // reverses that order.
02197         if( mScrollingPanelList )
02198         {
02199                 mScrollingPanelList->clearPanels();
02200                 param_map::iterator end = params.end();
02201                 for(param_map::iterator it = params.begin(); it != end; ++it)
02202                 {
02203                         mScrollingPanelList->addPanel( new LLScrollingPanelParam( "LLScrollingPanelParam", joint_mesh, (*it).second.second, (*it).second.first) );
02204                 }
02205         }
02206 }
02207 
02208 void LLFloaterCustomize::setWearable(EWearableType type, LLWearable* wearable, U32 perm_mask, BOOL is_complete)
02209 {
02210         llassert( type < WT_COUNT );
02211         gSavedSettings.setU32("AvatarSex", (gAgent.getAvatarObject()->getSex() == SEX_MALE) );
02212         
02213         LLPanelEditWearable* panel = mWearablePanelList[ type ];
02214         if( panel )
02215         {
02216                 panel->setWearable(wearable, perm_mask, is_complete);
02217                 updateScrollingPanelList((perm_mask & PERM_MODIFY) ? is_complete : FALSE);
02218         }
02219 }
02220 
02221 void LLFloaterCustomize::updateScrollingPanelList(BOOL allow_modify)
02222 {
02223         if( mScrollingPanelList )
02224         {
02225                 LLScrollingPanelParam::sUpdateDelayFrames = 0;
02226                 mScrollingPanelList->updatePanels(allow_modify );
02227         }
02228 }
02229 
02230 
02231 void LLFloaterCustomize::askToSaveAllIfDirty( void(*next_step_callback)(BOOL proceed, void* userdata), void* userdata )
02232 {
02233         if( isDirty())
02234         {
02235                 // Ask if user wants to save, then continue to next step afterwards
02236                 mNextStepAfterSaveAllCallback = next_step_callback;
02237                 mNextStepAfterSaveAllUserdata = userdata;
02238 
02239                 // Bring up view-modal dialog: Save changes? Yes, No, Cancel
02240                 gViewerWindow->alertXml("SaveClothingBodyChanges", 
02241                         LLFloaterCustomize::onSaveAllDialog, this);
02242                 return;
02243         }
02244 
02245         // Try to move to the next step
02246         if( next_step_callback )
02247         {
02248                 next_step_callback( TRUE, userdata );
02249         }
02250 }
02251 
02252 
02253 // static
02254 void LLFloaterCustomize::onSaveAllDialog( S32 option, void* userdata )
02255 {
02256         LLFloaterCustomize* self = (LLFloaterCustomize*) userdata;
02257 
02258         BOOL proceed = FALSE;
02259 
02260         switch( option )
02261         {
02262         case 0:  // "Save All"
02263                 gAgent.saveAllWearables();
02264                 proceed = TRUE;
02265                 break;
02266 
02267         case 1:  // "Don't Save"
02268                 {
02269 
02270                         EWearableType cur = getCurrentWearableType();
02271                         gAgent.revertAllWearables();
02272                         setCurrentWearableType( cur );
02273                         proceed = TRUE;
02274                 }
02275                 break;
02276 
02277         case 2: // "Cancel"
02278                 break;
02279 
02280         default:
02281                 llassert(0);
02282                 break;
02283         }
02284 
02285         if( self->mNextStepAfterSaveAllCallback )
02286         {
02287                 self->mNextStepAfterSaveAllCallback( proceed, self->mNextStepAfterSaveAllUserdata );
02288         }
02289 }
02290 
02291 // fetch observer
02292 class LLCurrentlyWorn : public LLInventoryFetchObserver
02293 {
02294 public:
02295         LLCurrentlyWorn() {}
02296         ~LLCurrentlyWorn() {}
02297         virtual void done() { /* no operation necessary */}
02298 };
02299 
02300 void LLFloaterCustomize::fetchInventory()
02301 {
02302         // Fetch currently worn items
02303         LLInventoryFetchObserver::item_ref_t ids;
02304         LLUUID item_id;
02305         for(S32 type = (S32)WT_SHAPE; type < (S32)WT_COUNT; ++type)
02306         {
02307                 item_id = gAgent.getWearableItem((EWearableType)type);
02308                 if(item_id.notNull())
02309                 {
02310                         ids.push_back(item_id);
02311                 }
02312         }
02313 
02314         // Fire & forget. The mInventoryObserver will catch inventory
02315         // updates and correct the UI as necessary.
02316         LLCurrentlyWorn worn;
02317         worn.fetchItems(ids);
02318 }
02319 
02320 void LLFloaterCustomize::updateInventoryUI()
02321 {
02322         BOOL all_complete = TRUE;
02323         BOOL is_complete = FALSE;
02324         U32 perm_mask = 0x0;
02325         LLPanelEditWearable* panel;
02326         LLViewerInventoryItem* item;
02327         for(S32 i = 0; i < WT_COUNT; ++i)
02328         {
02329                 item = NULL;
02330                 panel = mWearablePanelList[i];
02331                 if(panel)
02332                 {
02333                         item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(panel->getType());
02334                 }
02335                 if(item)
02336                 {
02337                         is_complete = item->isComplete();
02338                         if(!is_complete)
02339                         {
02340                                 all_complete = FALSE;
02341                         }
02342                         perm_mask = item->getPermissions().getMaskOwner();
02343                 }
02344                 else
02345                 {
02346                         is_complete = false;
02347                         perm_mask = 0x0;
02348                 }
02349                 if(i == sCurrentWearableType)
02350                 {
02351                         if(panel)
02352                         {
02353                                 panel->setUIPermissions(perm_mask, is_complete);
02354                         }
02355                         BOOL is_vis = panel && item && is_complete && (perm_mask & PERM_MODIFY);
02356                         childSetVisible("panel_container", is_vis);
02357                 }
02358         }
02359         childSetEnabled("Make Outfit", all_complete);
02360 }
02361 
02362 void LLFloaterCustomize::updateScrollingPanelUI()
02363 {
02364         LLPanelEditWearable* panel = mWearablePanelList[sCurrentWearableType];
02365         if(panel)
02366         {
02367                 LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(panel->getType());
02368                 if(item)
02369                 {
02370                         U32 perm_mask = item->getPermissions().getMaskOwner();
02371                         BOOL is_complete = item->isComplete();
02372                         updateScrollingPanelList((perm_mask & PERM_MODIFY) ? is_complete : FALSE);
02373                 }
02374         }
02375 }
02376 
02378 // LLUndoWearable
02379 
02380 void LLUndoWearable::setVisualParam( S32 param_id, F32 weight)
02381 {
02382         mAppearance.clear();
02383         mAppearance.addParam( param_id, weight );
02384 }
02385 
02386 void LLUndoWearable::setTexture( LLVOAvatar::ETextureIndex te, const LLUUID& asset_id )
02387 {
02388         mAppearance.clear();
02389         mAppearance.addTexture( te, asset_id );
02390 }
02391 
02392 void LLUndoWearable::setColor( LLVOAvatar::ETextureIndex te, const LLColor4& color )
02393 {
02394         LLVOAvatar* avatar = gAgent.getAvatarObject();
02395         if( !avatar )
02396         {
02397                 return;
02398         }
02399 
02400         const char* param_name[3];
02401         if( avatar->teToColorParams( te, param_name ) )
02402         {
02403                 mAppearance.clear();
02404                 LLVisualParam* param;
02405                 param = avatar->getVisualParam( param_name[0] );
02406                 if( param )
02407                 {
02408                         mAppearance.addParam( param->getID(), color.mV[VX] );
02409                 }
02410                 param = avatar->getVisualParam( param_name[1] );
02411                 if( param )
02412                 {
02413                         mAppearance.addParam( param->getID(), color.mV[VY] );
02414                 }
02415                 param = avatar->getVisualParam( param_name[2] );
02416                 if( param )
02417                 {
02418                         mAppearance.addParam( param->getID(), color.mV[VZ] );
02419                 }
02420         }
02421 }
02422 
02423 void LLUndoWearable::setWearable( EWearableType type )
02424 {
02425         LLVOAvatar* avatar = gAgent.getAvatarObject();
02426         if( !avatar )
02427         {
02428                 return;
02429         }
02430 
02431         mAppearance.clear();
02432 
02433         for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() )
02434         {
02435                 LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
02436                 if( (viewer_param->getWearableType() == type) && 
02437                         (viewer_param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) )
02438                 {
02439                         mAppearance.addParam( viewer_param->getID(), viewer_param->getWeight() );
02440                 }
02441         }
02442 
02443         for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ )
02444         {
02445                 if( LLVOAvatar::getTEWearableType( te ) == type )
02446                 {
02447                         LLViewerImage* te_image = avatar->getTEImage( te );
02448                         if( te_image )
02449                         {
02450                                 mAppearance.addTexture( te, te_image->getID() );
02451                         }
02452                 }
02453         }
02454 }
02455 
02456 
02457 void LLUndoWearable::applyUndoRedo()
02458 {
02459         LLVOAvatar* avatar = gAgent.getAvatarObject();
02460         if( !avatar )
02461         {
02462                 return;
02463         }
02464 
02465         ESex old_sex = avatar->getSex();
02466 
02467         // Parameters
02468         for (LLAppearance::param_map_t::iterator iter = mAppearance.mParamMap.begin();
02469                  iter != mAppearance.mParamMap.end(); ++iter)
02470         {
02471                 S32 param_id = iter->first;
02472                 F32 weight = iter->second;
02473                 F32 existing_weight = gAgent.getAvatarObject()->getVisualParamWeight( param_id );
02474                 avatar->setVisualParamWeight(param_id, weight, TRUE);
02475                 iter->second = existing_weight;
02476         }
02477 
02478         // Textures
02479         for( S32 i = 0; i < LLVOAvatar::TEX_NUM_ENTRIES; i++ )
02480         {
02481                 const LLUUID& image_id = mAppearance.mTextures[i];
02482                 if( !image_id.isNull() )
02483                 {
02484                         LLViewerImage* existing_image = avatar->getTEImage( i );
02485                         if( existing_image )
02486                         {
02487                                 const LLUUID& existing_asset_id = existing_image->getID();
02488                                 avatar->setLocTexTE( i, gImageList.getImage( mAppearance.mTextures[i] ), TRUE );
02489                                 mAppearance.mTextures[i] = existing_asset_id;
02490                         }
02491                 }
02492         }
02493 
02494         avatar->updateVisualParams();
02495         
02496         ESex new_sex = avatar->getSex();
02497         if( old_sex != new_sex )
02498         {
02499                 gSavedSettings.setU32( "AvatarSex", (new_sex == SEX_MALE) );
02500                 avatar->updateSexDependentLayerSets( TRUE );
02501         }       
02502         
02503         LLVisualParamHint::requestHintUpdates(); 
02504 
02505         if( gFloaterCustomize )
02506         {
02507                 gFloaterCustomize->updateScrollingPanelList(TRUE);
02508         }
02509 
02510         gAgent.sendAgentSetAppearance();
02511 }

Generated on Fri May 16 08:33:24 2008 for SecondLife by  doxygen 1.5.5