aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llfloatercustomize.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llfloatercustomize.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llfloatercustomize.cpp')
-rw-r--r--linden/indra/newview/llfloatercustomize.cpp2519
1 files changed, 2519 insertions, 0 deletions
diff --git a/linden/indra/newview/llfloatercustomize.cpp b/linden/indra/newview/llfloatercustomize.cpp
new file mode 100644
index 0000000..f564dad
--- /dev/null
+++ b/linden/indra/newview/llfloatercustomize.cpp
@@ -0,0 +1,2519 @@
1/**
2 * @file llfloatercustomize.cpp
3 * @brief The customize avatar floater, triggered by "Appearance..."
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llfloatercustomize.h"
31#include "llfontgl.h"
32#include "llbutton.h"
33#include "lliconctrl.h"
34#include "llresmgr.h"
35#include "llmorphview.h"
36#include "llfloatertools.h"
37#include "llagent.h"
38#include "lltoolmorph.h"
39#include "llvoavatar.h"
40#include "llradiogroup.h"
41#include "lltoolmgr.h"
42#include "llviewermenu.h"
43#include "llscrollcontainer.h"
44#include "llscrollingpanellist.h"
45#include "llsliderctrl.h"
46#include "lltabcontainervertical.h"
47#include "llviewerwindow.h"
48#include "llinventorymodel.h"
49#include "llinventoryview.h"
50#include "lltextbox.h"
51#include "lllineeditor.h"
52#include "llviewerimagelist.h"
53#include "llfocusmgr.h"
54#include "llviewerwindow.h"
55#include "llviewercamera.h"
56#include "llgenepool.h"
57#include "llappearance.h"
58#include "imageids.h"
59#include "llmodaldialog.h"
60#include "llassetstorage.h"
61#include "lltexturectrl.h"
62#include "lltextureentry.h"
63#include "llwearablelist.h"
64#include "llviewerinventory.h"
65#include "lldbstrings.h"
66#include "llcolorswatch.h"
67#include "llglheaders.h"
68#include "llui.h"
69#include "llviewermessage.h"
70#include "llimagejpeg.h"
71#include "llviewercontrol.h"
72#include "llvieweruictrlfactory.h"
73
74#include "llfilepicker.h"
75
76//XUI:translate : The ui xml for this really needs to be integrated with the appearance paramaters
77
78// Globals
79LLFloaterCustomize* gFloaterCustomize = NULL;
80
81const F32 PARAM_STEP_TIME_THRESHOLD = 0.25f;
82
83/////////////////////////////////////////////////////////////////////
84// LLUndoWearable
85
86class LLUndoWearable
87: public LLUndoAction
88{
89protected:
90 LLAppearance mAppearance;
91
92protected:
93 LLUndoWearable() {};
94 virtual ~LLUndoWearable(){};
95
96public:
97 static LLUndoAction *create() { return new LLUndoWearable(); }
98
99 void setVisualParam(S32 param_id, F32 weight);
100 void setColor( LLVOAvatar::ETextureIndex te, const LLColor4& color );
101 void setTexture( LLVOAvatar::ETextureIndex te, const LLUUID& asset_id );
102 void setWearable( EWearableType type );
103
104 virtual void undo() {applyUndoRedo();}
105 virtual void redo() {applyUndoRedo();}
106 void applyUndoRedo();
107};
108
109
110/////////////////////////////////////////////////////////////////////
111// LLFloaterCustomizeObserver
112
113class LLFloaterCustomizeObserver : public LLInventoryObserver
114{
115public:
116 LLFloaterCustomizeObserver(LLFloaterCustomize* fc) : mFC(fc) {}
117 virtual ~LLFloaterCustomizeObserver() {}
118 virtual void changed(U32 mask) { mFC->updateScrollingPanelUI(); }
119protected:
120 LLFloaterCustomize* mFC;
121};
122
123////////////////////////////////////////////////////////////////////////////
124
125// Local Constants
126
127class LLWearableSaveAsDialog : public LLModalDialog
128{
129private:
130 LLString mItemName;
131 void (*mCommitCallback)(LLWearableSaveAsDialog*,void*);
132 void* mCallbackUserData;
133
134public:
135 LLWearableSaveAsDialog( const LLString& desc, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata )
136 : LLModalDialog( "", 240, 100 ),
137 mCommitCallback( commit_cb ),
138 mCallbackUserData( userdata )
139 {
140 gUICtrlFactory->buildFloater(this, "floater_wearable_save_as.xml");
141
142 childSetAction("Save", LLWearableSaveAsDialog::onSave, this );
143 childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this );
144 childSetTextArg("name ed", "[DESC]", desc);
145 }
146
147 virtual void startModal()
148 {
149 LLModalDialog::startModal();
150 LLLineEditor* edit = LLUICtrlFactory::getLineEditorByName(this, "name ed");
151 if (!edit) return;
152 edit->setFocus(TRUE);
153 edit->selectAll();
154 }
155
156 const LLString& getItemName() { return mItemName; }
157
158 static void onSave( void* userdata )
159 {
160 LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata;
161 self->mItemName = self->childGetValue("name ed").asString();
162 LLString::trim(self->mItemName);
163 if( !self->mItemName.empty() )
164 {
165 if( self->mCommitCallback )
166 {
167 self->mCommitCallback( self, self->mCallbackUserData );
168 }
169 self->close(); // destroys this object
170 }
171 }
172
173 static void onCancel( void* userdata )
174 {
175 LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata;
176 self->close(); // destroys this object
177 }
178};
179
180////////////////////////////////////////////////////////////////////////////
181
182BOOL edit_wearable_for_teens(EWearableType type)
183{
184 switch(type)
185 {
186 case WT_UNDERSHIRT:
187 case WT_UNDERPANTS:
188 return FALSE;
189 default:
190 return TRUE;
191 }
192}
193
194class LLMakeOutfitDialog : public LLModalDialog
195{
196private:
197 LLString mFolderName;
198 void (*mCommitCallback)(LLMakeOutfitDialog*,void*);
199 void* mCallbackUserData;
200 std::vector<std::pair<std::string,S32> > mCheckBoxList;
201
202public:
203 LLMakeOutfitDialog( void(*commit_cb)(LLMakeOutfitDialog*,void*), void* userdata )
204 : LLModalDialog("",515, 510, TRUE ),
205 mCommitCallback( commit_cb ),
206 mCallbackUserData( userdata )
207 {
208 gUICtrlFactory->buildFloater(this, "floater_new_outfit_dialog.xml");
209
210 // Build list of check boxes
211 for( S32 i = 0; i < WT_COUNT; i++ )
212 {
213 LLString name = LLString("checkbox_") + LLWearable::typeToTypeLabel( (EWearableType)i );
214 mCheckBoxList.push_back(std::make_pair(name,i));
215 // Hide teen items
216 if (gAgent.mAccess < SIM_ACCESS_MATURE &&
217 !edit_wearable_for_teens((EWearableType)i))
218 {
219 // hide wearable checkboxes that don't apply to this account
220 LLString name = LLString("checkbox_") + LLWearable::typeToTypeLabel( (EWearableType)i );
221 childSetVisible(name, FALSE);
222 }
223 }
224
225 // NOTE: .xml needs to be updated if attachments are added or their names are changed!
226 LLVOAvatar* avatar = gAgent.getAvatarObject();
227 if( avatar )
228 {
229 for (LLViewerJointAttachment* attachment = avatar->mAttachmentPoints.getFirstData();
230 attachment;
231 attachment = gAgent.getAvatarObject()->mAttachmentPoints.getNextData())
232 {
233 BOOL object_attached = ( attachment->getNumObjects() > 0 );
234 S32 attachment_pt = avatar->mAttachmentPoints.getCurrentKeyWithoutIncrement();
235 LLString name = LLString("checkbox_") + attachment->getName();
236 mCheckBoxList.push_back(std::make_pair(name,attachment_pt));
237 childSetEnabled(name, object_attached);
238 }
239 }
240
241 childSetAction("Save", onSave, this );
242 childSetAction("Cancel", onCancel, this );
243 }
244
245 BOOL getRenameClothing()
246 {
247 return childGetValue("rename").asBoolean();
248
249 }
250 virtual void draw()
251 {
252 BOOL one_or_more_items_selected = FALSE;
253 for( S32 i = 0; i < (S32)mCheckBoxList.size(); i++ )
254 {
255 if( childGetValue(mCheckBoxList[i].first).asBoolean() )
256 {
257 one_or_more_items_selected = TRUE;
258 break;
259 }
260 }
261
262 childSetEnabled("Save", one_or_more_items_selected );
263
264 LLModalDialog::draw();
265 }
266
267 const LLString& getFolderName() { return mFolderName; }
268
269 void setWearableToInclude( S32 wearable, S32 enabled, S32 selected )
270 {
271 if( (0 <= wearable) && (wearable < WT_COUNT) )
272 {
273 LLString name = LLString("checkbox_") + LLWearable::typeToTypeLabel( (EWearableType)wearable );
274 childSetEnabled(name, enabled);
275 childSetValue(name, selected);
276 }
277 }
278
279 void getIncludedItems( LLDynamicArray<S32> &wearables_to_include, LLDynamicArray<S32> &attachments_to_include )
280 {
281 for( S32 i = 0; i < (S32)mCheckBoxList.size(); i++)
282 {
283 LLString name = mCheckBoxList[i].first;
284 BOOL checked = childGetValue(name).asBoolean();
285 if (i < WT_COUNT )
286 {
287 if( checked )
288 {
289 wearables_to_include.put(i);
290 }
291 }
292 else
293 {
294 if( checked )
295 {
296 S32 attachment_pt = mCheckBoxList[i].second;
297 attachments_to_include.put( attachment_pt );
298 }
299 }
300 }
301 }
302
303 static void onSave( void* userdata )
304 {
305 LLMakeOutfitDialog* self = (LLMakeOutfitDialog*) userdata;
306 self->mFolderName = self->childGetValue("name ed").asString();
307 LLString::trim(self->mFolderName);
308 if( !self->mFolderName.empty() )
309 {
310 if( self->mCommitCallback )
311 {
312 self->mCommitCallback( self, self->mCallbackUserData );
313 }
314 self->close(); // destroys this object
315 }
316 }
317
318 static void onCancel( void* userdata )
319 {
320 LLMakeOutfitDialog* self = (LLMakeOutfitDialog*) userdata;
321 self->close(); // destroys this object
322 }
323};
324
325/////////////////////////////////////////////////////////////////////
326// LLPanelEditWearable
327
328enum ESubpart {
329 SUBPART_SHAPE_HEAD = 1, // avoid 0
330 SUBPART_SHAPE_EYES,
331 SUBPART_SHAPE_EARS,
332 SUBPART_SHAPE_NOSE,
333 SUBPART_SHAPE_MOUTH,
334 SUBPART_SHAPE_CHIN,
335 SUBPART_SHAPE_TORSO,
336 SUBPART_SHAPE_LEGS,
337 SUBPART_SHAPE_WHOLE,
338 SUBPART_SHAPE_DETAIL,
339 SUBPART_SKIN_COLOR,
340 SUBPART_SKIN_FACEDETAIL,
341 SUBPART_SKIN_MAKEUP,
342 SUBPART_SKIN_BODYDETAIL,
343 SUBPART_HAIR_COLOR,
344 SUBPART_HAIR_STYLE,
345 SUBPART_HAIR_EYEBROWS,
346 SUBPART_HAIR_FACIAL,
347 SUBPART_EYES,
348 SUBPART_SHIRT,
349 SUBPART_PANTS,
350 SUBPART_SHOES,
351 SUBPART_SOCKS,
352 SUBPART_JACKET,
353 SUBPART_GLOVES,
354 SUBPART_UNDERSHIRT,
355 SUBPART_UNDERPANTS,
356 SUBPART_SKIRT
357 };
358
359struct LLSubpart
360{
361 LLSubpart() : mSex( SEX_BOTH ) {}
362
363 LLString mButtonName;
364 LLString mTargetJoint;
365 LLString mEditGroup;
366 LLVector3d mTargetOffset;
367 LLVector3d mCameraOffset;
368 ESex mSex;
369};
370
371////////////////////////////////////////////////////////////////////////////
372
373class LLPanelEditWearable : public LLPanel, public LLEditMenuHandler
374{
375public:
376 LLPanelEditWearable( EWearableType type );
377 virtual ~LLPanelEditWearable();
378
379 virtual BOOL postBuild();
380 virtual void draw();
381
382 void addSubpart(const LLString& name, ESubpart id, LLSubpart* part );
383 void addTextureDropTarget( LLVOAvatar::ETextureIndex te, const LLString& name, const LLUUID& default_image_id, BOOL allow_no_texture );
384 void addColorSwatch( LLVOAvatar::ETextureIndex te, const LLString& name );
385
386 const char* getLabel() { return LLWearable::typeToTypeLabel( mType ); }
387 EWearableType getType() { return mType; }
388
389 LLSubpart* getCurrentSubpart() { return mSubpartList[mCurrentSubpart]; }
390 ESubpart getDefaultSubpart();
391 void setSubpart( ESubpart subpart );
392 void switchToDefaultSubpart();
393
394 void setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete);
395
396 void addVisualParamToUndoBuffer( S32 param_id, F32 current_weight );
397 BOOL isDirty();
398
399 void setUIPermissions(U32 perm_mask, BOOL is_complete);
400
401 virtual void setVisible( BOOL visible );
402
403 // Inherted methods from LLEditMenuHandler
404 virtual void undo();
405 virtual BOOL canUndo();
406 virtual void redo();
407 virtual BOOL canRedo();
408
409 // Callbacks
410 static void onBtnSubpart( void* userdata );
411 static void onBtnTakeOff( void* userdata );
412 static void onBtnRandomize( void* userdata );
413 static void onBtnSave( void* userdata );
414
415 static void onBtnSaveAs( void* userdata );
416 static void onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata );
417
418 static void onBtnRevert( void* userdata );
419 static void onBtnTakeOffDialog( S32 option, void* userdata );
420 static void onBtnCreateNew( void* userdata );
421 static void onTextureCommit( LLUICtrl* ctrl, void* userdata );
422 static void onColorCommit( LLUICtrl* ctrl, void* userdata );
423 static void onCommitSexChange( LLUICtrl*, void* userdata );
424
425
426private:
427 EWearableType mType;
428 BOOL mCanTakeOff;
429 std::map<LLString, S32> mTextureList;
430 std::map<LLString, S32> mColorList;
431 std::map<ESubpart, LLSubpart*> mSubpartList;
432 ESubpart mCurrentSubpart;
433 LLUndoBuffer* mUndoBuffer;
434};
435
436////////////////////////////////////////////////////////////////////////////
437
438LLPanelEditWearable::LLPanelEditWearable( EWearableType type )
439 : LLPanel( LLWearable::typeToTypeLabel( type ) ),
440 mType( type )
441{
442 const S32 NUM_DISTORTION_UNDO_ENTRIES = 50;
443 mUndoBuffer = new LLUndoBuffer(LLUndoWearable::create, NUM_DISTORTION_UNDO_ENTRIES);
444}
445
446BOOL LLPanelEditWearable::postBuild()
447{
448 LLAssetType::EType asset_type = LLWearable::typeToAssetType( mType );
449 LLUUID icon_id( gViewerArt.getString(asset_type == LLAssetType::AT_CLOTHING ?
450 "inv_item_clothing.tga" :
451 "inv_item_bodypart.tga" ) );
452 childSetValue("icon", icon_id);
453
454 childSetAction("Create New", LLPanelEditWearable::onBtnCreateNew, this );
455
456 // If PG, can't take off underclothing or shirt
457 mCanTakeOff =
458 LLWearable::typeToAssetType( mType ) == LLAssetType::AT_CLOTHING &&
459 !( gAgent.mAccess < SIM_ACCESS_MATURE && (mType == WT_UNDERSHIRT || mType == WT_UNDERPANTS) );
460 childSetVisible("Take Off", mCanTakeOff);
461 childSetAction("Take Off", LLPanelEditWearable::onBtnTakeOff, this );
462
463 childSetAction("Save", &LLPanelEditWearable::onBtnSave, (void*)this );
464
465 childSetAction("Save As", &LLPanelEditWearable::onBtnSaveAs, (void*)this );
466
467 childSetAction("Revert", &LLPanelEditWearable::onBtnRevert, (void*)this );
468
469 return TRUE;
470}
471
472LLPanelEditWearable::~LLPanelEditWearable()
473{
474 delete mUndoBuffer;
475
476 std::for_each(mSubpartList.begin(), mSubpartList.end(), DeletePairedPointer());
477
478 // Route menu back to the default
479 if( gEditMenuHandler == this )
480 {
481 gEditMenuHandler = NULL;
482 }
483}
484
485void LLPanelEditWearable::addSubpart( const LLString& name, ESubpart id, LLSubpart* part )
486{
487 if (!name.empty())
488 {
489 childSetAction(name, &LLPanelEditWearable::onBtnSubpart, (void*)(S32)id);
490 part->mButtonName = name;
491 }
492 mSubpartList[id] = part;
493
494}
495
496// static
497void LLPanelEditWearable::onBtnSubpart(void* userdata)
498{
499 LLFloaterCustomize* floater_customize = gFloaterCustomize;
500 if (!floater_customize) return;
501 LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel();
502 if (!self) return;
503 ESubpart subpart = (ESubpart) (intptr_t)userdata;
504 self->setSubpart( subpart );
505}
506
507void LLPanelEditWearable::setSubpart( ESubpart subpart )
508{
509 mCurrentSubpart = subpart;
510
511 for (std::map<ESubpart, LLSubpart*>::iterator iter = mSubpartList.begin();
512 iter != mSubpartList.end(); ++iter)
513 {
514 LLButton* btn = LLUICtrlFactory::getButtonByName(this, iter->second->mButtonName);
515 if (btn)
516 {
517 btn->setToggleState( subpart == iter->first );
518 }
519 }
520
521 LLSubpart* part = get_if_there(mSubpartList, (ESubpart)subpart, (LLSubpart*)NULL);
522 if( part )
523 {
524 // Update the thumbnails we display
525 LLFloaterCustomize::param_map sorted_params;
526 LLVOAvatar* avatar = gAgent.getAvatarObject();
527 ESex avatar_sex = avatar->getSex();
528 LLViewerInventoryItem* item;
529 item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(mType);
530 U32 perm_mask = 0x0;
531 BOOL is_complete = FALSE;
532 if(item)
533 {
534 perm_mask = item->getPermissions().getMaskOwner();
535 is_complete = item->isComplete();
536 }
537 setUIPermissions(perm_mask, is_complete);
538 BOOL editable = ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE;
539
540 for(LLViewerVisualParam* param = (LLViewerVisualParam *)avatar->getFirstVisualParam();
541 param;
542 param = (LLViewerVisualParam *)avatar->getNextVisualParam())
543 {
544 if (param->getID() == -1
545 || param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE
546 || param->getEditGroup() != part->mEditGroup
547 || !(param->getSex() & avatar_sex))
548 {
549 continue;
550 }
551
552 // negative getDisplayOrder() to make lowest order the highest priority
553 LLFloaterCustomize::param_map::value_type vt(-param->getDisplayOrder(), LLFloaterCustomize::editable_param(editable, param));
554 llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates
555 sorted_params.insert(vt);
556 }
557 gFloaterCustomize->generateVisualParamHints(NULL, sorted_params);
558
559
560 // Update the camera
561 gMorphView->setCameraTargetJoint( gAgent.getAvatarObject()->getJoint( part->mTargetJoint ) );
562 gMorphView->setCameraTargetOffset( part->mTargetOffset );
563 gMorphView->setCameraOffset( part->mCameraOffset );
564 gMorphView->setCameraDistToDefault();
565 if (gSavedSettings.getBOOL("AppearanceCameraMovement"))
566 {
567 gMorphView->updateCamera();
568 }
569 }
570}
571
572// static
573void LLPanelEditWearable::onBtnRandomize( void* userdata )
574{
575 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
576
577 LLVOAvatar* avatar = gAgent.getAvatarObject();
578 LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(self->mType);
579 if(avatar
580 && item
581 && item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID())
582 && item->isComplete())
583 {
584 // Save current wearable parameters and textures to the undo buffer.
585 LLUndoWearable* action = (LLUndoWearable*)(self->mUndoBuffer->getNextAction());
586 action->setWearable( self->mType );
587
588 ESex old_sex = avatar->getSex();
589
590 gFloaterCustomize->spawnWearableAppearance( self->mType );
591
592 gFloaterCustomize->updateScrollingPanelList(TRUE);
593
594 ESex new_sex = avatar->getSex();
595 if( old_sex != new_sex )
596 {
597 // Updates radio button
598 gSavedSettings.setU32("AvatarSex", (new_sex == SEX_MALE) );
599
600 // Assumes that we're in the "Shape" Panel.
601 self->setSubpart( SUBPART_SHAPE_WHOLE );
602 }
603 }
604}
605
606
607// static
608void LLPanelEditWearable::onBtnTakeOff( void* userdata )
609{
610 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
611
612 LLWearable* wearable = gAgent.getWearable( self->mType );
613 if( !wearable )
614 {
615 return;
616 }
617
618 gAgent.removeWearable( self->mType );
619}
620
621// static
622void LLPanelEditWearable::onBtnSave( void* userdata )
623{
624 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
625 gAgent.saveWearable( self->mType );
626}
627
628// static
629void LLPanelEditWearable::onBtnSaveAs( void* userdata )
630{
631 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
632 LLWearable* wearable = gAgent.getWearable( self->getType() );
633 if( wearable )
634 {
635 LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self );
636 save_as_dialog->startModal();
637 // LLWearableSaveAsDialog deletes itself.
638 }
639}
640
641// static
642void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata )
643{
644 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
645 LLVOAvatar* avatar = gAgent.getAvatarObject();
646 if( avatar )
647 {
648 gAgent.saveWearableAs( self->getType(), save_as_dialog->getItemName(), FALSE );
649 }
650}
651
652
653// static
654void LLPanelEditWearable::onBtnRevert( void* userdata )
655{
656 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
657 gAgent.revertWearable( self->mType );
658}
659
660// static
661void LLPanelEditWearable::onBtnCreateNew( void* userdata )
662{
663 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
664 LLVOAvatar* avatar = gAgent.getAvatarObject();
665 if(avatar)
666 {
667 // Create a new wearable in the default folder for the wearable's asset type.
668 LLWearable* wearable = gWearableList.createNewWearable( self->getType() );
669 LLAssetType::EType asset_type = wearable->getAssetType();
670
671 LLUUID folder_id;
672 // regular UI, items get created in normal folder
673 folder_id = gInventory.findCategoryUUIDForType(asset_type);
674
675 LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback;
676 create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
677 folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(),
678 asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(),
679 wearable->getPermissions().getMaskNextOwner(), cb);
680 }
681}
682
683void LLPanelEditWearable::addColorSwatch( LLVOAvatar::ETextureIndex te, const LLString& name )
684{
685 childSetCommitCallback(name, LLPanelEditWearable::onColorCommit, this);
686 mColorList[name] = te;
687}
688
689// static
690void LLPanelEditWearable::onColorCommit( LLUICtrl* ctrl, void* userdata )
691{
692 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
693 LLColorSwatchCtrl* color_ctrl = (LLColorSwatchCtrl*) ctrl;
694
695 LLVOAvatar* avatar = gAgent.getAvatarObject();
696 if( avatar )
697 {
698 LLVOAvatar::ETextureIndex te = (LLVOAvatar::ETextureIndex)(self->mColorList[ctrl->getName()]);
699
700 LLColor4 old_color = avatar->getClothesColor( te );
701 const LLColor4& new_color = color_ctrl->get();
702 if( old_color != new_color )
703 {
704 // Save the old version to the undo stack
705 LLUndoWearable* action = (LLUndoWearable*)(self->mUndoBuffer->getNextAction());
706 action->setColor( te, old_color );
707
708 // Set the new version
709 avatar->setClothesColor( te, new_color, TRUE );
710 gAgent.sendAgentSetAppearance();
711
712 LLVisualParamHint::requestHintUpdates();
713 }
714 }
715}
716
717
718void LLPanelEditWearable::addTextureDropTarget( LLVOAvatar::ETextureIndex te, const LLString& name,
719 const LLUUID& default_image_id, BOOL allow_no_texture )
720{
721 childSetCommitCallback(name, LLPanelEditWearable::onTextureCommit, this);
722 LLTextureCtrl* texture_ctrl = LLViewerUICtrlFactory::getTexturePickerByName(this, name);
723 if (texture_ctrl)
724 {
725 texture_ctrl->setDefaultImageAssetID(default_image_id);
726 texture_ctrl->setAllowNoTexture( allow_no_texture );
727 // Don't allow (no copy) or (no transfer) textures to be selected.
728 texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER);
729 texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER);
730 }
731 mTextureList[name] = te;
732}
733
734// static
735void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata )
736{
737 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
738 LLTextureCtrl* texture_ctrl = (LLTextureCtrl*) ctrl;
739
740 LLVOAvatar* avatar = gAgent.getAvatarObject();
741 if( avatar )
742 {
743 LLVOAvatar::ETextureIndex te = (LLVOAvatar::ETextureIndex)(self->mTextureList[ctrl->getName()]);
744
745 // Save the old version to the undo stack
746 LLViewerImage* existing_image = avatar->getTEImage( te );
747 if( existing_image )
748 {
749 LLUndoWearable* action = (LLUndoWearable*)(self->mUndoBuffer->getNextAction());
750 action->setTexture( te, existing_image->getID() );
751 }
752
753 // Set the new version
754 LLViewerImage* image = gImageList.getImage( texture_ctrl->getImageAssetID() );
755 if( image->getID().isNull() )
756 {
757 image = gImageList.getImage(IMG_DEFAULT_AVATAR);
758 }
759 avatar->setLocTexTE( te, image, TRUE );
760 gAgent.sendAgentSetAppearance();
761 }
762}
763
764
765ESubpart LLPanelEditWearable::getDefaultSubpart()
766{
767 switch( mType )
768 {
769 case WT_SHAPE: return SUBPART_SHAPE_WHOLE;
770 case WT_SKIN: return SUBPART_SKIN_COLOR;
771 case WT_HAIR: return SUBPART_HAIR_COLOR;
772 case WT_EYES: return SUBPART_EYES;
773 case WT_SHIRT: return SUBPART_SHIRT;
774 case WT_PANTS: return SUBPART_PANTS;
775 case WT_SHOES: return SUBPART_SHOES;
776 case WT_SOCKS: return SUBPART_SOCKS;
777 case WT_JACKET: return SUBPART_JACKET;
778 case WT_GLOVES: return SUBPART_GLOVES;
779 case WT_UNDERSHIRT: return SUBPART_UNDERSHIRT;
780 case WT_UNDERPANTS: return SUBPART_UNDERPANTS;
781 case WT_SKIRT: return SUBPART_SKIRT;
782
783 default: llassert(0); return SUBPART_SHAPE_WHOLE;
784 }
785}
786
787
788void LLPanelEditWearable::draw()
789{
790 if( gFloaterCustomize->isMinimized() )
791 {
792 return;
793 }
794
795 LLVOAvatar* avatar = gAgent.getAvatarObject();
796 if( !avatar )
797 {
798 return;
799 }
800
801 if( getVisible() )
802 {
803 if( gFloaterCustomize->isFrontmost() && !gFocusMgr.getKeyboardFocus() )
804 {
805 // Route menu to this class
806 gEditMenuHandler = this;
807 }
808
809 LLWearable* wearable = gAgent.getWearable( mType );
810 BOOL has_wearable = (wearable != NULL );
811 BOOL is_dirty = isDirty();
812 BOOL is_modifiable = FALSE;
813 BOOL is_copyable = FALSE;
814 BOOL is_complete = FALSE;
815 LLViewerInventoryItem* item;
816 item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(mType);
817 if(item)
818 {
819 const LLPermissions& perm = item->getPermissions();
820 is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
821 is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID());
822 is_complete = item->isComplete();
823 }
824
825 childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty);
826 childSetEnabled("Save As", is_copyable && is_complete && has_wearable);
827 childSetEnabled("Revert", has_wearable && is_dirty );
828 childSetEnabled("Take Off", has_wearable );
829 childSetVisible("Take Off", mCanTakeOff );
830 childSetVisible("Create New", !has_wearable );
831
832 childSetVisible("not worn instructions", !has_wearable );
833 childSetVisible("no modify instructions", has_wearable && !is_modifiable);
834
835 for (std::map<ESubpart, LLSubpart*>::iterator iter = mSubpartList.begin();
836 iter != mSubpartList.end(); ++iter)
837 {
838 if( has_wearable && is_complete && is_modifiable )
839 {
840 childSetEnabled(iter->second->mButtonName, iter->second->mSex & avatar->getSex() );
841 }
842 else
843 {
844 childSetEnabled(iter->second->mButtonName, FALSE );
845 }
846 }
847
848 childSetVisible("square", !is_modifiable);
849
850 childSetVisible("title", FALSE);
851 childSetVisible("title_no_modify", FALSE);
852 childSetVisible("title_not_worn", FALSE);
853 childSetVisible("title_loading", FALSE);
854
855 childSetVisible("path", FALSE);
856
857 if(has_wearable && !is_modifiable)
858 {
859 childSetVisible("title_no_modify", TRUE);
860 childSetTextArg("title_no_modify", "[DESC]", LLWearable::typeToTypeLabel( mType ));
861
862 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
863 iter != mTextureList.end(); ++iter )
864 {
865 childSetVisible(iter->first, FALSE );
866 }
867 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
868 iter != mColorList.end(); ++iter )
869 {
870 childSetVisible(iter->first, FALSE );
871 }
872 }
873 else if(has_wearable && !is_complete)
874 {
875 childSetVisible("title_loading", TRUE);
876 childSetTextArg("title_loading", "[DESC]", LLWearable::typeToTypeLabel( mType ));
877
878 LLString path;
879 const LLUUID& item_id = gAgent.getWearableItem( wearable->getType() );
880 gInventory.appendPath(item_id, path);
881 childSetVisible("path", TRUE);
882 childSetTextArg("path", "[PATH]", path);
883
884 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
885 iter != mTextureList.end(); ++iter )
886 {
887 childSetVisible(iter->first, FALSE );
888 }
889 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
890 iter != mColorList.end(); ++iter )
891 {
892 childSetVisible(iter->first, FALSE );
893 }
894 }
895 else if(has_wearable && is_modifiable)
896 {
897 childSetVisible("title", TRUE);
898 childSetTextArg("title", "[DESC]", wearable->getName() );
899
900 LLString path;
901 const LLUUID& item_id = gAgent.getWearableItem( wearable->getType() );
902 gInventory.appendPath(item_id, path);
903 childSetVisible("path", TRUE);
904 childSetTextArg("path", "[PATH]", path);
905
906 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
907 iter != mTextureList.end(); ++iter )
908 {
909 LLString name = iter->first;
910 LLTextureCtrl* texture_ctrl = LLViewerUICtrlFactory::getTexturePickerByName(this, name);
911 S32 te_index = iter->second;
912 childSetVisible(name, is_copyable && is_modifiable && is_complete );
913 if (texture_ctrl)
914 {
915 const LLTextureEntry* te = avatar->getTE(te_index);
916 if( te && (te->getID() != IMG_DEFAULT_AVATAR) )
917 {
918 texture_ctrl->setImageAssetID( te->getID() );
919 }
920 else
921 {
922 texture_ctrl->setImageAssetID( LLUUID::null );
923 }
924 }
925 }
926
927 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
928 iter != mColorList.end(); ++iter )
929 {
930 LLString name = iter->first;
931 S32 te_index = iter->second;
932 childSetVisible(name, is_modifiable && is_complete );
933 childSetEnabled(name, is_modifiable && is_complete );
934 LLColorSwatchCtrl* ctrl = LLViewerUICtrlFactory::getColorSwatchByName(this, name);
935 if (ctrl)
936 {
937 ctrl->set(avatar->getClothesColor( (LLVOAvatar::ETextureIndex)te_index ) );
938 }
939 }
940 }
941 else
942 {
943 childSetVisible("title_not_worn", TRUE);
944 childSetTextArg("title_not_worn", "[DESC]", LLWearable::typeToTypeLabel( mType ));
945
946 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
947 iter != mTextureList.end(); ++iter )
948 {
949 childSetVisible(iter->first, FALSE );
950 }
951 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
952 iter != mColorList.end(); ++iter )
953 {
954 childSetVisible(iter->first, FALSE );
955 }
956 }
957
958 childSetVisible("icon", has_wearable && is_modifiable);
959
960 LLPanel::draw();
961 }
962}
963
964void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete)
965{
966 if( wearable )
967 {
968 setUIPermissions(perm_mask, is_complete);
969 }
970 mUndoBuffer->flushActions();
971}
972
973void LLPanelEditWearable::addVisualParamToUndoBuffer( S32 param_id, F32 current_weight )
974{
975 LLUndoWearable* action = (LLUndoWearable*)(mUndoBuffer->getNextAction());
976 action->setVisualParam( param_id, current_weight );
977}
978
979void LLPanelEditWearable::undo()
980{
981 mUndoBuffer->undoAction();
982}
983
984void LLPanelEditWearable::redo()
985{
986 mUndoBuffer->redoAction();
987}
988
989BOOL LLPanelEditWearable::canUndo()
990{
991 return mUndoBuffer->canUndo();
992}
993
994BOOL LLPanelEditWearable::canRedo()
995{
996 return mUndoBuffer->canRedo();
997}
998
999void LLPanelEditWearable::switchToDefaultSubpart()
1000{
1001 setSubpart( getDefaultSubpart() );
1002}
1003
1004void LLPanelEditWearable::setVisible(BOOL visible)
1005{
1006 LLPanel::setVisible( visible );
1007 if( !visible )
1008 {
1009 // Route menu back to the default
1010 if( gEditMenuHandler == this )
1011 {
1012 gEditMenuHandler = NULL;
1013 }
1014
1015 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
1016 iter != mColorList.end(); ++iter )
1017 {
1018 // this forces any open color pickers to cancel their selection
1019 childSetEnabled(iter->first, FALSE );
1020 }
1021 }
1022}
1023
1024BOOL LLPanelEditWearable::isDirty()
1025{
1026 LLWearable* wearable = gAgent.getWearable( mType );
1027 if( !wearable )
1028 {
1029 return FALSE;
1030 }
1031
1032 if( wearable->isDirty() )
1033 {
1034 return TRUE;
1035 }
1036
1037 return FALSE;
1038}
1039
1040// static
1041void LLPanelEditWearable::onCommitSexChange( LLUICtrl*, void* userdata )
1042{
1043 LLPanelEditWearable* self = (LLPanelEditWearable*) userdata;
1044
1045 LLVOAvatar* avatar = gAgent.getAvatarObject();
1046 if (!avatar)
1047 {
1048 return;
1049 }
1050
1051 if( !gAgent.isWearableModifiable(self->mType))
1052 {
1053 return;
1054 }
1055
1056 ESex new_sex = gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE;
1057
1058 LLViewerVisualParam* param = (LLViewerVisualParam*)avatar->getVisualParam( "male" );
1059 if( !param )
1060 {
1061 return;
1062 }
1063
1064 self->addVisualParamToUndoBuffer( param->getID(), param->getWeight() );
1065 param->setWeight( (new_sex == SEX_MALE), TRUE );
1066
1067 avatar->updateSexDependentLayerSets( TRUE );
1068
1069 avatar->updateVisualParams();
1070
1071 gFloaterCustomize->clearScrollingPanelList();
1072
1073 // Assumes that we're in the "Shape" Panel.
1074 self->setSubpart( SUBPART_SHAPE_WHOLE );
1075
1076 gAgent.sendAgentSetAppearance();
1077}
1078
1079void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete)
1080{
1081 BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE;
1082 BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE;
1083
1084 childSetEnabled("Save", is_modifiable && is_complete);
1085 childSetEnabled("Save As", is_copyable && is_complete);
1086 childSetEnabled("Randomize", is_modifiable && is_complete);
1087 childSetEnabled("sex radio", is_modifiable && is_complete);
1088 for( std::map<LLString, S32>::iterator iter = mTextureList.begin();
1089 iter != mTextureList.end(); ++iter )
1090 {
1091 childSetVisible(iter->first, is_copyable && is_modifiable && is_complete );
1092 }
1093 for( std::map<LLString, S32>::iterator iter = mColorList.begin();
1094 iter != mColorList.end(); ++iter )
1095 {
1096 childSetVisible(iter->first, is_modifiable && is_complete );
1097 }
1098}
1099
1100/////////////////////////////////////////////////////////////////////
1101// LLScrollingPanelParam
1102
1103class LLScrollingPanelParam : public LLScrollingPanel
1104{
1105public:
1106 LLScrollingPanelParam( const LLString& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify );
1107 virtual ~LLScrollingPanelParam();
1108
1109 virtual void draw();
1110 virtual void setVisible( BOOL visible );
1111 virtual void updatePanel(BOOL allow_modify);
1112
1113 static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata);
1114 static void onSliderMoved(LLUICtrl* ctrl, void* userdata);
1115 static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata);
1116
1117 static void onHintMinMouseDown(void* userdata);
1118 static void onHintMinHeldDown(void* userdata);
1119 static void onHintMaxMouseDown(void* userdata);
1120 static void onHintMaxHeldDown(void* userdata);
1121 static void onHintMinMouseUp(void* userdata);
1122 static void onHintMaxMouseUp(void* userdata);
1123
1124 void onHintMouseDown( LLVisualParamHint* hint );
1125 void onHintHeldDown( LLVisualParamHint* hint );
1126
1127 F32 weightToPercent( F32 weight );
1128 F32 percentToWeight( F32 percent );
1129
1130public:
1131 LLViewerVisualParam* mParam;
1132 LLVisualParamHint* mHintMin;
1133 LLVisualParamHint* mHintMax;
1134 static S32 sUpdateDelayFrames;
1135
1136protected:
1137 LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint.
1138 F32 mLastHeldTime;
1139
1140 BOOL mAllowModify;
1141};
1142
1143//static
1144S32 LLScrollingPanelParam::sUpdateDelayFrames = 0;
1145
1146const S32 BTN_BORDER = 2;
1147const S32 PARAM_HINT_WIDTH = 128;
1148const S32 PARAM_HINT_HEIGHT = 128;
1149const S32 PARAM_HINT_LABEL_HEIGHT = 16;
1150const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH);
1151const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH;
1152
1153LLScrollingPanelParam::LLScrollingPanelParam( const LLString& name,
1154 LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify )
1155 : LLScrollingPanel( name, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 ) ),
1156 mParam(param),
1157 mAllowModify(allow_modify)
1158{
1159 gUICtrlFactory->buildPanel(this, "panel_scrolling_param.xml");
1160
1161 S32 pos_x = 2 * LLPANEL_BORDER_WIDTH;
1162 S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT;
1163 F32 min_weight = param->getMinWeight();
1164 F32 max_weight = param->getMaxWeight();
1165
1166 mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight);
1167 pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER;
1168 mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight );
1169
1170 mHintMin->setAllowsUpdates( FALSE );
1171 mHintMax->setAllowsUpdates( FALSE );
1172 childSetValue("param slider", weightToPercent(param->getWeight()));
1173 childSetLabelArg("param slider", "[DESC]", param->getDisplayName());
1174 childSetEnabled("param slider", mAllowModify);
1175 childSetCommitCallback("param slider", LLScrollingPanelParam::onSliderMoved, this);
1176
1177 // XUI:translate
1178 LLString min_name = param->getMinDisplayName();
1179 LLString max_name = param->getMaxDisplayName();
1180 childSetValue("min param text", min_name);
1181 childSetValue("max param text", max_name);
1182
1183 LLButton* less = LLUICtrlFactory::getButtonByName(this, "less");
1184 if (less)
1185 {
1186 less->setMouseDownCallback( LLScrollingPanelParam::onHintMinMouseDown );
1187 less->setMouseUpCallback( LLScrollingPanelParam::onHintMinMouseUp );
1188 less->setHeldDownCallback( LLScrollingPanelParam::onHintMinHeldDown );
1189 less->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD );
1190 }
1191
1192 LLButton* more = LLUICtrlFactory::getButtonByName(this, "more");
1193 if (more)
1194 {
1195 more->setMouseDownCallback( LLScrollingPanelParam::onHintMaxMouseDown );
1196 more->setMouseUpCallback( LLScrollingPanelParam::onHintMaxMouseUp );
1197 more->setHeldDownCallback( LLScrollingPanelParam::onHintMaxHeldDown );
1198 more->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD );
1199 }
1200
1201 setVisible(FALSE);
1202 setBorderVisible( FALSE );
1203}
1204
1205LLScrollingPanelParam::~LLScrollingPanelParam()
1206{
1207 delete mHintMin;
1208 delete mHintMax;
1209}
1210
1211void LLScrollingPanelParam::updatePanel(BOOL allow_modify)
1212{
1213 LLViewerVisualParam* param = mHintMin->getVisualParam();
1214 childSetValue("param slider", weightToPercent( param->getWeight() ) );
1215 mHintMin->requestUpdate( sUpdateDelayFrames++ );
1216 mHintMax->requestUpdate( sUpdateDelayFrames++ );
1217
1218 mAllowModify = allow_modify;
1219 childSetEnabled("param slider", mAllowModify);
1220 childSetEnabled("less", mAllowModify);
1221 childSetEnabled("more", mAllowModify);
1222}
1223
1224void LLScrollingPanelParam::setVisible( BOOL visible )
1225{
1226 if( getVisible() != visible )
1227 {
1228 LLPanel::setVisible( visible );
1229 mHintMin->setAllowsUpdates( visible );
1230 mHintMax->setAllowsUpdates( visible );
1231
1232 if( visible )
1233 {
1234 mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ );
1235 mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ );
1236 }
1237 }
1238}
1239
1240void LLScrollingPanelParam::draw()
1241{
1242 if( gFloaterCustomize->isMinimized() )
1243 {
1244 return;
1245 }
1246
1247 childSetVisible("less", mHintMin->getVisible());
1248 childSetVisible("more", mHintMax->getVisible());
1249
1250 if( getVisible() )
1251 {
1252 // Draw all the children except for the labels
1253 childSetVisible( "min param text", FALSE );
1254 childSetVisible( "max param text", FALSE );
1255 LLPanel::draw();
1256
1257 // Draw the hints over the "less" and "more" buttons.
1258 glPushMatrix();
1259 {
1260 const LLRect& r = mHintMin->getRect();
1261 F32 left = (F32)(r.mLeft + BTN_BORDER);
1262 F32 bot = (F32)(r.mBottom + BTN_BORDER);
1263 glTranslatef(left, bot, 0.f);
1264 mHintMin->draw();
1265 }
1266 glPopMatrix();
1267
1268 glPushMatrix();
1269 {
1270 const LLRect& r = mHintMax->getRect();
1271 F32 left = (F32)(r.mLeft + BTN_BORDER);
1272 F32 bot = (F32)(r.mBottom + BTN_BORDER);
1273 glTranslatef(left, bot, 0.f);
1274 mHintMax->draw();
1275 }
1276 glPopMatrix();
1277
1278
1279 // Draw labels on top of the buttons
1280 childSetVisible( "min param text", TRUE );
1281 drawChild(getChildByName("min param text"), BTN_BORDER, BTN_BORDER);
1282
1283 childSetVisible( "max param text", TRUE );
1284 drawChild(getChildByName("max param text"), BTN_BORDER, BTN_BORDER);
1285 }
1286}
1287
1288// static
1289void LLScrollingPanelParam::onSliderMoved(LLUICtrl* ctrl, void* userdata)
1290{
1291 LLSliderCtrl* slider = (LLSliderCtrl*) ctrl;
1292 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1293 LLViewerVisualParam* param = self->mParam;
1294
1295 F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( param );
1296 F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() );
1297 if (current_weight != new_weight )
1298 {
1299 gAgent.getAvatarObject()->setVisualParamWeight( param, new_weight, TRUE);
1300 gAgent.getAvatarObject()->updateVisualParams();
1301 }
1302}
1303
1304// static
1305void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata)
1306{
1307 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1308 LLViewerVisualParam* param = self->mParam;
1309
1310 // store existing values in undo buffer
1311 F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( param );
1312
1313 if( gFloaterCustomize )
1314 {
1315 LLPanelEditWearable* panel = gFloaterCustomize->getCurrentWearablePanel();
1316 if( panel )
1317 {
1318 panel->addVisualParamToUndoBuffer( param->getID(), current_weight );
1319 }
1320 }
1321}
1322
1323// static
1324void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata)
1325{
1326 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1327
1328 // store namevalue
1329 gAgent.sendAgentSetAppearance();
1330
1331 LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax );
1332}
1333
1334// static
1335void LLScrollingPanelParam::onHintMinMouseDown( void* userdata )
1336{
1337 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1338 self->onHintMouseDown( self->mHintMin );
1339}
1340
1341// static
1342void LLScrollingPanelParam::onHintMaxMouseDown( void* userdata )
1343{
1344 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1345 self->onHintMouseDown( self->mHintMax );
1346}
1347
1348
1349void LLScrollingPanelParam::onHintMouseDown( LLVisualParamHint* hint )
1350{
1351 // morph towards this result
1352 F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( hint->getVisualParam() );
1353
1354 // if we have maxed out on this morph, we shouldn't be able to click it
1355 if( hint->getVisualParamWeight() != current_weight )
1356 {
1357 // store existing values in undo buffer
1358 if( gFloaterCustomize )
1359 {
1360 LLPanelEditWearable* panel = gFloaterCustomize->getCurrentWearablePanel();
1361 if( panel )
1362 {
1363 panel->addVisualParamToUndoBuffer( hint->getVisualParam()->getID(), current_weight );
1364 }
1365 }
1366
1367 mMouseDownTimer.reset();
1368 mLastHeldTime = 0.f;
1369 }
1370}
1371
1372// static
1373void LLScrollingPanelParam::onHintMinHeldDown( void* userdata )
1374{
1375 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1376 self->onHintHeldDown( self->mHintMin );
1377}
1378
1379// static
1380void LLScrollingPanelParam::onHintMaxHeldDown( void* userdata )
1381{
1382 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1383 self->onHintHeldDown( self->mHintMax );
1384}
1385
1386void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint )
1387{
1388 F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( hint->getVisualParam() );
1389
1390 if (current_weight != hint->getVisualParamWeight() )
1391 {
1392 const F32 FULL_BLEND_TIME = 2.f;
1393 F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime;
1394 mLastHeldTime += elapsed_time;
1395
1396 F32 new_weight;
1397 if (current_weight > hint->getVisualParamWeight() )
1398 {
1399 new_weight = current_weight - (elapsed_time / FULL_BLEND_TIME);
1400 }
1401 else
1402 {
1403 new_weight = current_weight + (elapsed_time / FULL_BLEND_TIME);
1404 }
1405
1406 // Make sure we're not taking the slider out of bounds
1407 // (this is where some simple UI limits are stored)
1408 F32 new_percent = weightToPercent(new_weight);
1409 LLSliderCtrl* slider = LLUICtrlFactory::getSliderByName(this, "param slider");
1410 if (slider)
1411 {
1412 if (slider->getMinValue() < new_percent
1413 && new_percent < slider->getMaxValue())
1414 {
1415 gAgent.getAvatarObject()->setVisualParamWeight( hint->getVisualParam(), new_weight, TRUE);
1416 gAgent.getAvatarObject()->updateVisualParams();
1417
1418 slider->setValue( weightToPercent( new_weight ) );
1419 }
1420 }
1421 }
1422}
1423
1424// static
1425void LLScrollingPanelParam::onHintMinMouseUp( void* userdata )
1426{
1427 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1428
1429 F32 elapsed_time = self->mMouseDownTimer.getElapsedTimeF32();
1430
1431 LLVOAvatar* avatar = gAgent.getAvatarObject();
1432 if (avatar)
1433 {
1434 LLVisualParamHint* hint = self->mHintMin;
1435
1436 if (elapsed_time < PARAM_STEP_TIME_THRESHOLD)
1437 {
1438 // step in direction
1439 F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( hint->getVisualParam() );
1440 F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight();
1441 // step a fraction in the negative directiona
1442 F32 new_weight = current_weight - (range / 10.f);
1443 F32 new_percent = self->weightToPercent(new_weight);
1444 LLSliderCtrl* slider = LLUICtrlFactory::getSliderByName(self, "param slider");
1445 if (slider)
1446 {
1447 if (slider->getMinValue() < new_percent
1448 && new_percent < slider->getMaxValue())
1449 {
1450 avatar->setVisualParamWeight(hint->getVisualParam(), new_weight, TRUE);
1451 slider->setValue( self->weightToPercent( new_weight ) );
1452 }
1453 }
1454 }
1455
1456 // store namevalue
1457 gAgent.sendAgentSetAppearance();
1458 }
1459
1460 LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax );
1461}
1462
1463void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata )
1464{
1465 LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
1466
1467 F32 elapsed_time = self->mMouseDownTimer.getElapsedTimeF32();
1468
1469 LLVOAvatar* avatar = gAgent.getAvatarObject();
1470 if (avatar)
1471 {
1472 LLVisualParamHint* hint = self->mHintMax;
1473
1474 if (elapsed_time < PARAM_STEP_TIME_THRESHOLD)
1475 {
1476 // step in direction
1477 F32 current_weight = gAgent.getAvatarObject()->getVisualParamWeight( hint->getVisualParam() );
1478 F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight();
1479 // step a fraction in the negative direction
1480 F32 new_weight = current_weight + (range / 10.f);
1481 F32 new_percent = self->weightToPercent(new_weight);
1482 LLSliderCtrl* slider = LLUICtrlFactory::getSliderByName(self, "param slider");
1483 if (slider)
1484 {
1485 if (slider->getMinValue() < new_percent
1486 && new_percent < slider->getMaxValue())
1487 {
1488 avatar->setVisualParamWeight(hint->getVisualParam(), new_weight, TRUE);
1489 slider->setValue( self->weightToPercent( new_weight ) );
1490 }
1491 }
1492 }
1493
1494 // store namevalue
1495 gAgent.sendAgentSetAppearance();
1496 }
1497
1498 LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax );
1499}
1500
1501
1502F32 LLScrollingPanelParam::weightToPercent( F32 weight )
1503{
1504 LLViewerVisualParam* param = mParam;
1505 return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f;
1506}
1507
1508F32 LLScrollingPanelParam::percentToWeight( F32 percent )
1509{
1510 LLViewerVisualParam* param = mParam;
1511 return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight();
1512}
1513
1514const LLString& LLFloaterCustomize::getEditGroup()
1515{
1516 return getCurrentWearablePanel()->getCurrentSubpart()->mEditGroup;
1517}
1518
1519
1520/////////////////////////////////////////////////////////////////////
1521// LLFloaterCustomize
1522
1523// statics
1524EWearableType LLFloaterCustomize::sCurrentWearableType = WT_SHAPE;
1525
1526struct WearablePanelData
1527{
1528 WearablePanelData(LLFloaterCustomize* floater, EWearableType type)
1529 : mFloater(floater), mType(type) {}
1530 LLFloaterCustomize* mFloater;
1531 EWearableType mType;
1532};
1533
1534LLFloaterCustomize::LLFloaterCustomize()
1535: LLFloater("customize"),
1536 mScrollingPanelList( NULL ),
1537 mGenePool( NULL ),
1538 mInventoryObserver(NULL),
1539 mNextStepAfterSaveAllCallback( NULL ),
1540 mNextStepAfterSaveAllUserdata( NULL )
1541{
1542 gSavedSettings.setU32("AvatarSex", (gAgent.getAvatarObject()->getSex() == SEX_MALE) );
1543
1544 mResetParams = new LLVisualParamReset();
1545
1546 // create the observer which will watch for matching incoming inventory
1547 mInventoryObserver = new LLFloaterCustomizeObserver(this);
1548 gInventory.addObserver(mInventoryObserver);
1549
1550 LLCallbackMap::map_t factory_map;
1551 factory_map["Shape"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SHAPE) ) );
1552 factory_map["Skin"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SKIN) ) );
1553 factory_map["Hair"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_HAIR) ) );
1554 factory_map["Eyes"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_EYES) ) );
1555 factory_map["Shirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SHIRT) ) );
1556 factory_map["Pants"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_PANTS) ) );
1557 factory_map["Shoes"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SHOES) ) );
1558 factory_map["Socks"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SOCKS) ) );
1559 factory_map["Jacket"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_JACKET) ) );
1560 factory_map["Gloves"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_GLOVES) ) );
1561 factory_map["Undershirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_UNDERSHIRT) ) );
1562 factory_map["Underpants"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_UNDERPANTS) ) );
1563 factory_map["Skirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SKIRT) ) );
1564
1565 gUICtrlFactory->buildFloater(this, "floater_customize.xml", &factory_map);
1566
1567}
1568
1569BOOL LLFloaterCustomize::postBuild()
1570{
1571 childSetAction("Make Outfit", LLFloaterCustomize::onBtnMakeOutfit, (void*)this);
1572 childSetAction("Save All", LLFloaterCustomize::onBtnSaveAll, (void*)this);
1573 childSetAction("Close", LLFloater::onClickClose, (void*)this);
1574
1575 // Wearable panels
1576 initWearablePanels();
1577
1578 // Tab container
1579 childSetTabChangeCallback("customize tab container", "Shape", onTabChanged, (void*)(S32)WT_SHAPE );
1580 childSetTabChangeCallback("customize tab container", "Skin", onTabChanged, (void*)(S32)WT_SKIN );
1581 childSetTabChangeCallback("customize tab container", "Hair", onTabChanged, (void*)(S32)WT_HAIR );
1582 childSetTabChangeCallback("customize tab container", "Eyes", onTabChanged, (void*)(S32)WT_EYES );
1583 childSetTabChangeCallback("customize tab container", "Shirt", onTabChanged, (void*)(S32)WT_SHIRT );
1584 childSetTabChangeCallback("customize tab container", "Pants", onTabChanged, (void*)(S32)WT_PANTS );
1585 childSetTabChangeCallback("customize tab container", "Shoes", onTabChanged, (void*)(S32)WT_SHOES );
1586 childSetTabChangeCallback("customize tab container", "Socks", onTabChanged, (void*)(S32)WT_SOCKS );
1587 childSetTabChangeCallback("customize tab container", "Jacket", onTabChanged, (void*)(S32)WT_JACKET );
1588 childSetTabChangeCallback("customize tab container", "Gloves", onTabChanged, (void*)(S32)WT_GLOVES );
1589 childSetTabChangeCallback("customize tab container", "Undershirt", onTabChanged, (void*)(S32)WT_UNDERSHIRT );
1590 childSetTabChangeCallback("customize tab container", "Underpants", onTabChanged, (void*)(S32)WT_UNDERPANTS );
1591 childSetTabChangeCallback("customize tab container", "Skirt", onTabChanged, (void*)(S32)WT_SKIRT );
1592
1593 // Remove underware panels for teens
1594 if (gAgent.mAccess < SIM_ACCESS_MATURE)
1595 {
1596 LLTabContainerCommon* tab_container = LLUICtrlFactory::getTabContainerByName(this, "customize tab container");
1597 if (tab_container)
1598 {
1599 LLPanel* panel;
1600 panel = tab_container->getPanelByName("Undershirt");
1601 if (panel) tab_container->removeTabPanel(panel);
1602 panel = tab_container->getPanelByName("Underpants");
1603 if (panel) tab_container->removeTabPanel(panel);
1604 }
1605 }
1606
1607 // Scrolling Panel
1608 initScrollingPanelList();
1609
1610 childShowTab("customize tab container", "Shape", true);
1611
1612 return TRUE;
1613}
1614
1615////////////////////////////////////////////////////////////////////////////
1616
1617// static
1618void LLFloaterCustomize::setCurrentWearableType( EWearableType type )
1619{
1620 if( LLFloaterCustomize::sCurrentWearableType != type )
1621 {
1622 LLFloaterCustomize::sCurrentWearableType = type;
1623
1624 S32 type_int = (S32)type;
1625 if( gFloaterCustomize
1626 && gFloaterCustomize->mWearablePanelList[type_int])
1627 {
1628 LLString panelname = gFloaterCustomize->mWearablePanelList[type_int]->getName();
1629 gFloaterCustomize->childShowTab("customize tab container", panelname);
1630 gFloaterCustomize->switchToDefaultSubpart();
1631 }
1632 }
1633}
1634
1635// static
1636void LLFloaterCustomize::onBtnSaveAll( void* userdata )
1637{
1638 gAgent.saveAllWearables();
1639}
1640
1641
1642// static
1643void LLFloaterCustomize::onBtnSnapshot( void* userdata )
1644{
1645 // Trigger noise, but not animation
1646 send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
1647
1648 LLPointer<LLImageRaw> raw = new LLImageRaw;
1649 BOOL success = gViewerWindow->rawSnapshot(raw,
1650 gViewerWindow->getWindowWidth(),
1651 gViewerWindow->getWindowHeight(),
1652 TRUE, // keep window aspect ratio
1653 FALSE, // UI in snapshot off
1654 FALSE); // do_rebuild off
1655 if (!success) return;
1656
1657 LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
1658 success = jpeg_image->encode(raw);
1659 if(!success) return;
1660
1661 LLString filepath("C:\\snapshot");
1662 filepath += ".jpg";
1663
1664 success = jpeg_image->save(filepath);
1665}
1666
1667// static
1668void LLFloaterCustomize::onBtnMakeOutfit( void* userdata )
1669{
1670 LLVOAvatar* avatar = gAgent.getAvatarObject();
1671 if(avatar)
1672 {
1673 LLMakeOutfitDialog* dialog = new LLMakeOutfitDialog( onMakeOutfitCommit, NULL );
1674 // LLMakeOutfitDialog deletes itself.
1675
1676 for( S32 i = 0; i < WT_COUNT; i++ )
1677 {
1678 BOOL enabled = (gAgent.getWearable( (EWearableType) i ) != NULL);
1679 BOOL selected = (enabled && (WT_SHIRT <= i) && (i < WT_COUNT)); // only select clothing by default
1680 if (gAgent.mAccess < SIM_ACCESS_MATURE
1681 && !edit_wearable_for_teens((EWearableType)i))
1682 {
1683 dialog->setWearableToInclude( i, FALSE, FALSE );
1684 }
1685 else
1686 {
1687 dialog->setWearableToInclude( i, enabled, selected );
1688 }
1689 }
1690 dialog->startModal();
1691 }
1692}
1693
1694// static
1695void LLFloaterCustomize::onMakeOutfitCommit( LLMakeOutfitDialog* dialog, void* userdata )
1696{
1697 LLVOAvatar* avatar = gAgent.getAvatarObject();
1698 if(avatar)
1699 {
1700 LLDynamicArray<S32> wearables_to_include;
1701 LLDynamicArray<S32> attachments_to_include; // attachment points
1702
1703 dialog->getIncludedItems( wearables_to_include, attachments_to_include );
1704
1705 gAgent.makeNewOutfit( dialog->getFolderName(), wearables_to_include, attachments_to_include, dialog->getRenameClothing() );
1706 }
1707}
1708
1709////////////////////////////////////////////////////////////////////////////
1710
1711// static
1712void* LLFloaterCustomize::createWearablePanel(void* userdata)
1713{
1714 WearablePanelData* data = (WearablePanelData*)userdata;
1715 EWearableType type = data->mType;
1716 LLPanelEditWearable* panel;
1717 if ((gAgent.mAccess < SIM_ACCESS_MATURE && !edit_wearable_for_teens(data->mType) ))
1718 {
1719 panel = NULL;
1720 }
1721 else
1722 {
1723 panel = new LLPanelEditWearable( type );
1724 }
1725 data->mFloater->mWearablePanelList[type] = panel;
1726 delete data;
1727 return panel;
1728}
1729
1730void LLFloaterCustomize::initWearablePanels()
1731{
1732 LLSubpart* part;
1733
1734 /////////////////////////////////////////
1735 // Shape
1736 LLPanelEditWearable* panel = mWearablePanelList[ WT_SHAPE ];
1737
1738 // body
1739 part = new LLSubpart();
1740 part->mTargetJoint = "mPelvis";
1741 part->mEditGroup = "shape_body";
1742 part->mTargetOffset.setVec(0.f, 0.f, 0.1f);
1743 part->mCameraOffset.setVec(-2.5f, 0.5f, 0.8f);
1744 panel->addSubpart( "Body", SUBPART_SHAPE_WHOLE, part );
1745
1746 // head supparts
1747 part = new LLSubpart();
1748 part->mTargetJoint = "mHead";
1749 part->mEditGroup = "shape_head";
1750 part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
1751 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
1752 panel->addSubpart( "Head", SUBPART_SHAPE_HEAD, part );
1753
1754 part = new LLSubpart();
1755 part->mTargetJoint = "mHead";
1756 part->mEditGroup = "shape_eyes";
1757 part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
1758 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
1759 panel->addSubpart( "Eyes", SUBPART_SHAPE_EYES, part );
1760
1761 part = new LLSubpart();
1762 part->mTargetJoint = "mHead";
1763 part->mEditGroup = "shape_ears";
1764 part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
1765 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
1766 panel->addSubpart( "Ears", SUBPART_SHAPE_EARS, part );
1767
1768 part = new LLSubpart();
1769 part->mTargetJoint = "mHead";
1770 part->mEditGroup = "shape_nose";
1771 part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
1772 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
1773 panel->addSubpart( "Nose", SUBPART_SHAPE_NOSE, part );
1774
1775
1776 part = new LLSubpart();
1777 part->mTargetJoint = "mHead";
1778 part->mEditGroup = "shape_mouth";
1779 part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
1780 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
1781 panel->addSubpart( "Mouth", SUBPART_SHAPE_MOUTH, part );
1782
1783
1784 part = new LLSubpart();
1785 part->mTargetJoint = "mHead";
1786 part->mEditGroup = "shape_chin";
1787 part->mTargetOffset.setVec(0.f, 0.f, 0.05f );
1788 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f );
1789 panel->addSubpart( "Chin", SUBPART_SHAPE_CHIN, part );
1790
1791 // torso
1792 part = new LLSubpart();
1793 part->mTargetJoint = "mTorso";
1794 part->mEditGroup = "shape_torso";
1795 part->mTargetOffset.setVec(0.f, 0.f, 0.3f);
1796 part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f);
1797 panel->addSubpart( "Torso", SUBPART_SHAPE_TORSO, part );
1798
1799 // legs
1800 part = new LLSubpart();
1801 part->mTargetJoint = "mPelvis";
1802 part->mEditGroup = "shape_legs";
1803 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
1804 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
1805 panel->addSubpart( "Legs", SUBPART_SHAPE_LEGS, part );
1806
1807 panel->childSetCommitCallback("sex radio", LLPanelEditWearable::onCommitSexChange, panel);
1808 panel->childSetAction("Randomize", &LLPanelEditWearable::onBtnRandomize, panel);
1809
1810 /////////////////////////////////////////
1811 // Skin
1812 panel = mWearablePanelList[ WT_SKIN ];
1813
1814 part = new LLSubpart();
1815 part->mTargetJoint = "mHead";
1816 part->mEditGroup = "skin_color";
1817 part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
1818 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
1819 panel->addSubpart( "Skin Color", SUBPART_SKIN_COLOR, part );
1820
1821 part = new LLSubpart();
1822 part->mTargetJoint = "mHead";
1823 part->mEditGroup = "skin_facedetail";
1824 part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
1825 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
1826 panel->addSubpart( "Face Detail", SUBPART_SKIN_FACEDETAIL, part );
1827
1828 part = new LLSubpart();
1829 part->mTargetJoint = "mHead";
1830 part->mEditGroup = "skin_makeup";
1831 part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
1832 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
1833 panel->addSubpart( "Makeup", SUBPART_SKIN_MAKEUP, part );
1834
1835 part = new LLSubpart();
1836 part->mTargetJoint = "mPelvis";
1837 part->mEditGroup = "skin_bodydetail";
1838 part->mTargetOffset.setVec(0.f, 0.f, -0.2f);
1839 part->mCameraOffset.setVec(-2.5f, 0.5f, 0.5f);
1840 panel->addSubpart( "Body Detail", SUBPART_SKIN_BODYDETAIL, part );
1841
1842 panel->addTextureDropTarget( LLVOAvatar::TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE );
1843 panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE );
1844 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE );
1845
1846 panel->childSetAction("Randomize", &LLPanelEditWearable::onBtnRandomize, panel);
1847
1848 /////////////////////////////////////////
1849 // Hair
1850 panel = mWearablePanelList[ WT_HAIR ];
1851
1852 part = new LLSubpart();
1853 part->mTargetJoint = "mHead";
1854 part->mEditGroup = "hair_color";
1855 part->mTargetOffset.setVec(0.f, 0.f, 0.10f);
1856 part->mCameraOffset.setVec(-0.4f, 0.05f, 0.10f);
1857 panel->addSubpart( "Color", SUBPART_HAIR_COLOR, part );
1858
1859 part = new LLSubpart();
1860 part->mTargetJoint = "mHead";
1861 part->mEditGroup = "hair_style";
1862 part->mTargetOffset.setVec(0.f, 0.f, 0.10f);
1863 part->mCameraOffset.setVec(-0.4f, 0.05f, 0.10f);
1864 panel->addSubpart( "Style", SUBPART_HAIR_STYLE, part );
1865
1866 part = new LLSubpart();
1867 part->mTargetJoint = "mHead";
1868 part->mEditGroup = "hair_eyebrows";
1869 part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
1870 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
1871 panel->addSubpart( "Eyebrows", SUBPART_HAIR_EYEBROWS, part );
1872
1873 part = new LLSubpart();
1874 part->mSex = SEX_MALE;
1875 part->mTargetJoint = "mHead";
1876 part->mEditGroup = "hair_facial";
1877 part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
1878 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
1879 panel->addSubpart( "Facial", SUBPART_HAIR_FACIAL, part );
1880
1881 panel->addTextureDropTarget(LLVOAvatar::TEX_HAIR, "Texture",
1882 LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ),
1883 FALSE );
1884
1885 panel->childSetAction("Randomize", &LLPanelEditWearable::onBtnRandomize, panel);
1886
1887 /////////////////////////////////////////
1888 // Eyes
1889 panel = mWearablePanelList[ WT_EYES ];
1890
1891 part = new LLSubpart();
1892 part->mTargetJoint = "mHead";
1893 part->mEditGroup = "eyes";
1894 part->mTargetOffset.setVec(0.f, 0.f, 0.05f);
1895 part->mCameraOffset.setVec(-0.5f, 0.05f, 0.07f);
1896 panel->addSubpart( "", SUBPART_EYES, part );
1897
1898 panel->addTextureDropTarget(LLVOAvatar::TEX_EYES_IRIS, "Iris",
1899 LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ),
1900 FALSE );
1901
1902 panel->childSetAction("Randomize", &LLPanelEditWearable::onBtnRandomize, panel);
1903
1904 /////////////////////////////////////////
1905 // Shirt
1906 panel = mWearablePanelList[ WT_SHIRT ];
1907
1908 part = new LLSubpart();
1909 part->mTargetJoint = "mTorso";
1910 part->mEditGroup = "shirt";
1911 part->mTargetOffset.setVec(0.f, 0.f, 0.3f);
1912 part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f);
1913 panel->addSubpart( "", SUBPART_SHIRT, part );
1914
1915 panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_SHIRT, "Fabric",
1916 LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ),
1917 FALSE );
1918
1919 panel->addColorSwatch( LLVOAvatar::TEX_UPPER_SHIRT, "Color/Tint" );
1920
1921
1922 /////////////////////////////////////////
1923 // Pants
1924 panel = mWearablePanelList[ WT_PANTS ];
1925
1926 part = new LLSubpart();
1927 part->mTargetJoint = "mPelvis";
1928 part->mEditGroup = "pants";
1929 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
1930 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
1931 panel->addSubpart( "", SUBPART_PANTS, part );
1932
1933 panel->addTextureDropTarget(LLVOAvatar::TEX_LOWER_PANTS, "Fabric",
1934 LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ),
1935 FALSE );
1936
1937 panel->addColorSwatch( LLVOAvatar::TEX_LOWER_PANTS, "Color/Tint" );
1938
1939
1940 /////////////////////////////////////////
1941 // Shoes
1942 panel = mWearablePanelList[ WT_SHOES ];
1943
1944 if (panel)
1945 {
1946 part = new LLSubpart();
1947 part->mTargetJoint = "mPelvis";
1948 part->mEditGroup = "shoes";
1949 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
1950 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
1951 panel->addSubpart( "", SUBPART_SHOES, part );
1952
1953 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_SHOES, "Fabric",
1954 LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ),
1955 FALSE );
1956
1957 panel->addColorSwatch( LLVOAvatar::TEX_LOWER_SHOES, "Color/Tint" );
1958 }
1959
1960
1961 /////////////////////////////////////////
1962 // Socks
1963 panel = mWearablePanelList[ WT_SOCKS ];
1964
1965 if (panel)
1966 {
1967 part = new LLSubpart();
1968 part->mTargetJoint = "mPelvis";
1969 part->mEditGroup = "socks";
1970 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
1971 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
1972 panel->addSubpart( "", SUBPART_SOCKS, part );
1973
1974 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_SOCKS, "Fabric",
1975 LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ),
1976 FALSE );
1977
1978 panel->addColorSwatch( LLVOAvatar::TEX_LOWER_SOCKS, "Color/Tint" );
1979 }
1980
1981 /////////////////////////////////////////
1982 // Jacket
1983 panel = mWearablePanelList[ WT_JACKET ];
1984
1985 if (panel)
1986 {
1987 part = new LLSubpart();
1988 part->mTargetJoint = "mTorso";
1989 part->mEditGroup = "jacket";
1990 part->mTargetOffset.setVec(0.f, 0.f, 0.f);
1991 part->mCameraOffset.setVec(-2.f, 0.1f, 0.3f);
1992 panel->addSubpart( "", SUBPART_JACKET, part );
1993
1994 panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_JACKET, "Upper Fabric",
1995 LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ),
1996 FALSE );
1997 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_JACKET, "Lower Fabric",
1998 LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ),
1999 FALSE );
2000
2001 panel->addColorSwatch( LLVOAvatar::TEX_UPPER_JACKET, "Color/Tint" );
2002 }
2003
2004 /////////////////////////////////////////
2005 // Skirt
2006 panel = mWearablePanelList[ WT_SKIRT ];
2007
2008 if (panel)
2009 {
2010 part = new LLSubpart();
2011 part->mTargetJoint = "mPelvis";
2012 part->mEditGroup = "skirt";
2013 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
2014 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
2015 panel->addSubpart( "", SUBPART_SKIRT, part );
2016
2017 panel->addTextureDropTarget( LLVOAvatar::TEX_SKIRT, "Fabric",
2018 LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ),
2019 FALSE );
2020
2021 panel->addColorSwatch( LLVOAvatar::TEX_SKIRT, "Color/Tint" );
2022 }
2023
2024
2025 /////////////////////////////////////////
2026 // Gloves
2027 panel = mWearablePanelList[ WT_GLOVES ];
2028
2029 if (panel)
2030 {
2031 part = new LLSubpart();
2032 part->mTargetJoint = "mTorso";
2033 part->mEditGroup = "gloves";
2034 part->mTargetOffset.setVec(0.f, 0.f, 0.f);
2035 part->mCameraOffset.setVec(-1.f, 0.15f, 0.f);
2036 panel->addSubpart( "", SUBPART_GLOVES, part );
2037
2038 panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_GLOVES, "Fabric",
2039 LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ),
2040 FALSE );
2041
2042 panel->addColorSwatch( LLVOAvatar::TEX_UPPER_GLOVES, "Color/Tint" );
2043 }
2044
2045
2046 /////////////////////////////////////////
2047 // Undershirt
2048 panel = mWearablePanelList[ WT_UNDERSHIRT ];
2049
2050 if (panel)
2051 {
2052 part = new LLSubpart();
2053 part->mTargetJoint = "mTorso";
2054 part->mEditGroup = "undershirt";
2055 part->mTargetOffset.setVec(0.f, 0.f, 0.3f);
2056 part->mCameraOffset.setVec(-1.f, 0.15f, 0.3f);
2057 panel->addSubpart( "", SUBPART_UNDERSHIRT, part );
2058
2059 panel->addTextureDropTarget( LLVOAvatar::TEX_UPPER_UNDERSHIRT, "Fabric",
2060 LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ),
2061 FALSE );
2062
2063 panel->addColorSwatch( LLVOAvatar::TEX_UPPER_UNDERSHIRT, "Color/Tint" );
2064 }
2065
2066 /////////////////////////////////////////
2067 // Underpants
2068 panel = mWearablePanelList[ WT_UNDERPANTS ];
2069
2070 if (panel)
2071 {
2072 part = new LLSubpart();
2073 part->mTargetJoint = "mPelvis";
2074 part->mEditGroup = "underpants";
2075 part->mTargetOffset.setVec(0.f, 0.f, -0.5f);
2076 part->mCameraOffset.setVec(-1.6f, 0.15f, -0.5f);
2077 panel->addSubpart( "", SUBPART_UNDERPANTS, part );
2078
2079 panel->addTextureDropTarget( LLVOAvatar::TEX_LOWER_UNDERPANTS, "Fabric",
2080 LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ),
2081 FALSE );
2082
2083 panel->addColorSwatch( LLVOAvatar::TEX_LOWER_UNDERPANTS, "Color/Tint" );
2084 }
2085}
2086
2087////////////////////////////////////////////////////////////////////////////
2088
2089LLFloaterCustomize::~LLFloaterCustomize()
2090{
2091 llinfos << "Destroying LLFloaterCustomize" << llendl;
2092 delete mGenePool;
2093 delete mResetParams;
2094 gInventory.removeObserver(mInventoryObserver);
2095 delete mInventoryObserver;
2096}
2097
2098void LLFloaterCustomize::switchToDefaultSubpart()
2099{
2100 getCurrentWearablePanel()->switchToDefaultSubpart();
2101}
2102
2103void LLFloaterCustomize::spawnWearableAppearance(EWearableType type)
2104{
2105 if( !mGenePool )
2106 {
2107 mGenePool = new LLGenePool();
2108 }
2109
2110 LLVOAvatar* avatar = gAgent.getAvatarObject();
2111 if( avatar )
2112 {
2113 mGenePool->spawn( type );
2114 }
2115}
2116
2117
2118void LLFloaterCustomize::draw()
2119{
2120 if( isMinimized() )
2121 {
2122 LLFloater::draw();
2123 return;
2124 }
2125
2126 // only do this if we are in the customize avatar mode
2127 // and not transitioning into or out of it
2128 if( getVisible() )
2129 {
2130 // *TODO: This is a sort of expensive call, which only needs
2131 // to be called when the tabs change or an inventory item
2132 // arrives. Figure out some way to avoid this if possible.
2133 updateInventoryUI();
2134
2135 LLScrollingPanelParam::sUpdateDelayFrames = 0;
2136
2137 childSetEnabled("Save All", isDirty() );
2138 LLFloater::draw();
2139 }
2140}
2141
2142BOOL LLFloaterCustomize::isDirty()
2143{
2144 for(S32 i = 0; i < WT_COUNT; i++)
2145 {
2146 if( mWearablePanelList[i]
2147 && mWearablePanelList[i]->isDirty() )
2148 {
2149 return TRUE;
2150 }
2151 }
2152 return FALSE;
2153}
2154
2155
2156// static
2157void LLFloaterCustomize::onTabChanged( void* userdata, bool from_click )
2158{
2159 EWearableType wearable_type = (EWearableType) (intptr_t)userdata;
2160 LLFloaterCustomize::setCurrentWearableType( wearable_type );
2161}
2162
2163void LLFloaterCustomize::onClose(bool app_quitting)
2164{
2165 handle_reset_view(); // Calls askToSaveAllIfDirty
2166}
2167
2168
2169////////////////////////////////////////////////////////////////////////////
2170
2171const S32 LOWER_BTN_HEIGHT = 18 + 8;
2172
2173const S32 FLOATER_CUSTOMIZE_BUTTON_WIDTH = 82;
2174const S32 FLOATER_CUSTOMIZE_BOTTOM_PAD = 30;
2175const S32 LINE_HEIGHT = 16;
2176const S32 HEADER_PAD = 8;
2177const S32 HEADER_HEIGHT = 3 * (LINE_HEIGHT + LLFLOATER_VPAD) + (2 * LLPANEL_BORDER_WIDTH) + HEADER_PAD;
2178
2179void LLFloaterCustomize::initScrollingPanelList()
2180{
2181 LLScrollableContainerView* scroll_container =
2182 LLUICtrlFactory::getScrollableContainerByName(this, "panel_container");
2183 // LLScrollingPanelList's do not import correctly
2184// mScrollingPanelList = LLUICtrlFactory::getScrollingPanelList(this, "panel_list");
2185 mScrollingPanelList = new LLScrollingPanelList("panel_list", LLRect());
2186 if (scroll_container)
2187 {
2188 scroll_container->setScrolledView(mScrollingPanelList);
2189 scroll_container->addChild(mScrollingPanelList);
2190 }
2191}
2192
2193void LLFloaterCustomize::clearScrollingPanelList()
2194{
2195 if( mScrollingPanelList )
2196 {
2197 mScrollingPanelList->clearPanels();
2198 }
2199}
2200
2201void LLFloaterCustomize::generateVisualParamHints(LLViewerJointMesh* joint_mesh, LLFloaterCustomize::param_map& params)
2202{
2203 // sorted_params is sorted according to magnitude of effect from
2204 // least to greatest. Adding to the front of the child list
2205 // reverses that order.
2206 if( mScrollingPanelList )
2207 {
2208 mScrollingPanelList->clearPanels();
2209 param_map::iterator end = params.end();
2210 for(param_map::iterator it = params.begin(); it != end; ++it)
2211 {
2212 mScrollingPanelList->addPanel( new LLScrollingPanelParam( "LLScrollingPanelParam", joint_mesh, (*it).second.second, (*it).second.first) );
2213 }
2214 }
2215}
2216
2217void LLFloaterCustomize::setWearable(EWearableType type, LLWearable* wearable, U32 perm_mask, BOOL is_complete)
2218{
2219 llassert( type < WT_COUNT );
2220 gSavedSettings.setU32("AvatarSex", (gAgent.getAvatarObject()->getSex() == SEX_MALE) );
2221
2222 LLPanelEditWearable* panel = mWearablePanelList[ type ];
2223 if( panel )
2224 {
2225 panel->setWearable(wearable, perm_mask, is_complete);
2226 updateScrollingPanelList((perm_mask & PERM_MODIFY) ? is_complete : FALSE);
2227 }
2228}
2229
2230void LLFloaterCustomize::updateScrollingPanelList(BOOL allow_modify)
2231{
2232 if( mScrollingPanelList )
2233 {
2234 LLScrollingPanelParam::sUpdateDelayFrames = 0;
2235 mScrollingPanelList->updatePanels(allow_modify );
2236 }
2237}
2238
2239
2240void LLFloaterCustomize::askToSaveAllIfDirty( void(*next_step_callback)(BOOL proceed, void* userdata), void* userdata )
2241{
2242 if( isDirty())
2243 {
2244 // Ask if user wants to save, then continue to next step afterwards
2245 mNextStepAfterSaveAllCallback = next_step_callback;
2246 mNextStepAfterSaveAllUserdata = userdata;
2247
2248 // Bring up view-modal dialog: Save changes? Yes, No, Cancel
2249 gViewerWindow->alertXml("SaveClothingBodyChanges",
2250 LLFloaterCustomize::onSaveAllDialog, this);
2251 return;
2252 }
2253
2254 // Try to move to the next step
2255 if( next_step_callback )
2256 {
2257 next_step_callback( TRUE, userdata );
2258 }
2259}
2260
2261
2262// static
2263void LLFloaterCustomize::onSaveAllDialog( S32 option, void* userdata )
2264{
2265 LLFloaterCustomize* self = (LLFloaterCustomize*) userdata;
2266
2267 BOOL proceed = FALSE;
2268
2269 switch( option )
2270 {
2271 case 0: // "Save All"
2272 gAgent.saveAllWearables();
2273 proceed = TRUE;
2274 break;
2275
2276 case 1: // "Don't Save"
2277 {
2278
2279 EWearableType cur = getCurrentWearableType();
2280 gAgent.revertAllWearables();
2281 setCurrentWearableType( cur );
2282 proceed = TRUE;
2283 }
2284 break;
2285
2286 case 2: // "Cancel"
2287 break;
2288
2289 default:
2290 llassert(0);
2291 break;
2292 }
2293
2294 if( self->mNextStepAfterSaveAllCallback )
2295 {
2296 self->mNextStepAfterSaveAllCallback( proceed, self->mNextStepAfterSaveAllUserdata );
2297 }
2298}
2299
2300// fetch observer
2301class LLCurrentlyWorn : public LLInventoryFetchObserver
2302{
2303public:
2304 LLCurrentlyWorn() {}
2305 ~LLCurrentlyWorn() {}
2306 virtual void done() { /* no operation necessary */}
2307};
2308
2309void LLFloaterCustomize::fetchInventory()
2310{
2311 // Fetch currently worn items
2312 LLInventoryFetchObserver::item_ref_t ids;
2313 LLUUID item_id;
2314 for(S32 type = (S32)WT_SHAPE; type < (S32)WT_COUNT; ++type)
2315 {
2316 item_id = gAgent.getWearableItem((EWearableType)type);
2317 if(item_id.notNull())
2318 {
2319 ids.push_back(item_id);
2320 }
2321 }
2322
2323 // Fire & forget. The mInventoryObserver will catch inventory
2324 // updates and correct the UI as necessary.
2325 LLCurrentlyWorn worn;
2326 worn.fetchItems(ids);
2327}
2328
2329void LLFloaterCustomize::updateInventoryUI()
2330{
2331 BOOL all_complete = TRUE;
2332 BOOL is_complete = FALSE;
2333 U32 perm_mask = 0x0;
2334 LLPanelEditWearable* panel;
2335 LLViewerInventoryItem* item;
2336 for(S32 i = 0; i < WT_COUNT; ++i)
2337 {
2338 item = NULL;
2339 panel = mWearablePanelList[i];
2340 if(panel)
2341 {
2342 item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(panel->getType());
2343 }
2344 if(item)
2345 {
2346 is_complete = item->isComplete();
2347 if(!is_complete)
2348 {
2349 all_complete = FALSE;
2350 }
2351 perm_mask = item->getPermissions().getMaskOwner();
2352 }
2353 else
2354 {
2355 is_complete = false;
2356 perm_mask = 0x0;
2357 }
2358 if(i == sCurrentWearableType)
2359 {
2360 if(panel)
2361 {
2362 panel->setUIPermissions(perm_mask, is_complete);
2363 }
2364 BOOL is_vis = panel && item && is_complete && (perm_mask & PERM_MODIFY);
2365 childSetVisible("panel_container", is_vis);
2366 }
2367 }
2368 childSetEnabled("Make Outfit", all_complete);
2369}
2370
2371void LLFloaterCustomize::updateScrollingPanelUI()
2372{
2373 LLPanelEditWearable* panel = mWearablePanelList[sCurrentWearableType];
2374 if(panel)
2375 {
2376 LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgent.getWearableInventoryItem(panel->getType());
2377 if(item)
2378 {
2379 U32 perm_mask = item->getPermissions().getMaskOwner();
2380 BOOL is_complete = item->isComplete();
2381 updateScrollingPanelList((perm_mask & PERM_MODIFY) ? is_complete : FALSE);
2382 }
2383 }
2384}
2385
2386/////////////////////////////////////////////////////////////////////
2387// LLUndoWearable
2388
2389void LLUndoWearable::setVisualParam( S32 param_id, F32 weight)
2390{
2391 mAppearance.clear();
2392 mAppearance.addParam( param_id, weight );
2393}
2394
2395void LLUndoWearable::setTexture( LLVOAvatar::ETextureIndex te, const LLUUID& asset_id )
2396{
2397 mAppearance.clear();
2398 mAppearance.addTexture( te, asset_id );
2399}
2400
2401void LLUndoWearable::setColor( LLVOAvatar::ETextureIndex te, const LLColor4& color )
2402{
2403 LLVOAvatar* avatar = gAgent.getAvatarObject();
2404 if( !avatar )
2405 {
2406 return;
2407 }
2408
2409 const char* param_name[3];
2410 if( avatar->teToColorParams( te, param_name ) )
2411 {
2412 mAppearance.clear();
2413 LLVisualParam* param;
2414 param = avatar->getVisualParam( param_name[0] );
2415 if( param )
2416 {
2417 mAppearance.addParam( param->getID(), color.mV[VX] );
2418 }
2419 param = avatar->getVisualParam( param_name[1] );
2420 if( param )
2421 {
2422 mAppearance.addParam( param->getID(), color.mV[VY] );
2423 }
2424 param = avatar->getVisualParam( param_name[2] );
2425 if( param )
2426 {
2427 mAppearance.addParam( param->getID(), color.mV[VZ] );
2428 }
2429 }
2430}
2431
2432void LLUndoWearable::setWearable( EWearableType type )
2433{
2434 LLVOAvatar* avatar = gAgent.getAvatarObject();
2435 if( !avatar )
2436 {
2437 return;
2438 }
2439
2440 mAppearance.clear();
2441
2442 for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() )
2443 {
2444 LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
2445 if( (viewer_param->getWearableType() == type) &&
2446 (viewer_param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) )
2447 {
2448 mAppearance.addParam( viewer_param->getID(), viewer_param->getWeight() );
2449 }
2450 }
2451
2452 for( S32 te = 0; te < LLVOAvatar::TEX_NUM_ENTRIES; te++ )
2453 {
2454 if( LLVOAvatar::getTEWearableType( te ) == type )
2455 {
2456 LLViewerImage* te_image = avatar->getTEImage( te );
2457 if( te_image )
2458 {
2459 mAppearance.addTexture( te, te_image->getID() );
2460 }
2461 }
2462 }
2463}
2464
2465
2466void LLUndoWearable::applyUndoRedo()
2467{
2468 LLVOAvatar* avatar = gAgent.getAvatarObject();
2469 if( !avatar )
2470 {
2471 return;
2472 }
2473
2474 ESex old_sex = avatar->getSex();
2475
2476 // Parameters
2477 for( F32* weightp = mAppearance.mParamMap.getFirstData(); weightp; weightp = mAppearance.mParamMap.getNextData() )
2478 {
2479 S32 param_id = mAppearance.mParamMap.getCurrentKeyWithoutIncrement();
2480
2481 F32 existing_weight = gAgent.getAvatarObject()->getVisualParamWeight( param_id );
2482 avatar->setVisualParamWeight(param_id, *weightp, TRUE);
2483 *weightp = existing_weight;
2484 }
2485
2486 // Textures
2487 for( S32 i = 0; i < LLVOAvatar::TEX_NUM_ENTRIES; i++ )
2488 {
2489 const LLUUID& image_id = mAppearance.mTextures[i];
2490 if( !image_id.isNull() )
2491 {
2492 LLViewerImage* existing_image = avatar->getTEImage( i );
2493 if( existing_image )
2494 {
2495 const LLUUID& existing_asset_id = existing_image->getID();
2496 avatar->setLocTexTE( i, gImageList.getImage( mAppearance.mTextures[i] ), TRUE );
2497 mAppearance.mTextures[i] = existing_asset_id;
2498 }
2499 }
2500 }
2501
2502 avatar->updateVisualParams();
2503
2504 ESex new_sex = avatar->getSex();
2505 if( old_sex != new_sex )
2506 {
2507 gSavedSettings.setU32( "AvatarSex", (new_sex == SEX_MALE) );
2508 avatar->updateSexDependentLayerSets( TRUE );
2509 }
2510
2511 LLVisualParamHint::requestHintUpdates();
2512
2513 if( gFloaterCustomize )
2514 {
2515 gFloaterCustomize->updateScrollingPanelList(TRUE);
2516 }
2517
2518 gAgent.sendAgentSetAppearance();
2519}