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

Generated on Thu Jul 1 06:08:32 2010 for Second Life Viewer by  doxygen 1.4.7