llpaneleditwearable.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259
  1. /**
  2. * @file llpaneleditwearable.cpp
  3. * @brief A LLPanel dedicated to the editing of wearables.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llpaneleditwearable.h"
  34. #include "imageids.h"
  35. #include "llbutton.h"
  36. #include "llcheckboxctrl.h"
  37. #include "lliconctrl.h"
  38. #include "llnotifications.h"
  39. #include "llspinctrl.h"
  40. #include "lltextbox.h"
  41. #include "lluictrlfactory.h"
  42. #include "llvisualparam.h"
  43. #include "llxmltree.h"
  44. #include "llagent.h"
  45. #include "llagentwearables.h"
  46. #include "llappearancemgr.h"
  47. #include "llcolorswatch.h"
  48. #include "llfloatercustomize.h"
  49. #include "llinventoryicon.h"
  50. #include "llmorphview.h"
  51. #include "lltexturectrl.h"
  52. #include "llviewercontrol.h"
  53. #include "llviewerinventory.h"
  54. #include "llvisualparamhint.h"
  55. #include "llwearablelist.h"
  56. using namespace LLAvatarAppearanceDefines;
  57. LLPanelEditWearable::LLPanelEditWearable(LLWearableType::EType type)
  58. : LLPanel(LLWearableType::getTypeLabel(type)),
  59. mType(type),
  60. mLayer(0), // Use the first layer by default
  61. mSpinLayer(NULL),
  62. mButtonImport(NULL),
  63. mButtonCreateNew(NULL),
  64. mButtonSave(NULL),
  65. mButtonSaveAs(NULL),
  66. mButtonRevert(NULL),
  67. mButtonTakeOff(NULL),
  68. mSexRadio(NULL),
  69. mLockIcon(NULL),
  70. mWearableIcon(NULL),
  71. mNotWornInstructions(NULL),
  72. mNoModifyInstructions(NULL),
  73. mTitle(NULL),
  74. mTitleNoModify(NULL),
  75. mTitleNotWorn(NULL),
  76. mTitleLoading(NULL),
  77. mPath(NULL)
  78. {
  79. mWearable = gAgentWearables.getViewerWearable(type, mLayer);
  80. }
  81. bool LLPanelEditWearable::postBuild()
  82. {
  83. mSpinLayer = getChild<LLSpinCtrl>("layer", true, false);
  84. if (mSpinLayer)
  85. {
  86. if ((gSavedSettings.getBool("NoMultiplePhysics") &&
  87. mType == LLWearableType::WT_PHYSICS) ||
  88. (gSavedSettings.getBool("NoMultipleShoes") &&
  89. mType == LLWearableType::WT_SHOES) ||
  90. (gSavedSettings.getBool("NoMultipleSkirts") &&
  91. mType == LLWearableType::WT_SKIRT))
  92. {
  93. mSpinLayer->setVisible(false);
  94. mSpinLayer = NULL;
  95. }
  96. else
  97. {
  98. setMaxLayers();
  99. mSpinLayer->set((F32)mLayer);
  100. mSpinLayer->setCommitCallback(onCommitLayer);
  101. mSpinLayer->setCallbackUserData(this);
  102. }
  103. }
  104. mLockIcon = getChild<LLIconCtrl>("lock", true, false);
  105. mWearableIcon = getChild<LLIconCtrl>("icon", true, false);
  106. if (mWearableIcon)
  107. {
  108. LLAssetType::EType asset_type = LLWearableType::getAssetType(mType);
  109. std::string icon_name =
  110. LLInventoryIcon::getIconName(asset_type,
  111. LLInventoryType::IT_WEARABLE,
  112. mType, false);
  113. mWearableIcon->setValue(icon_name);
  114. }
  115. mNotWornInstructions = getChild<LLTextBox>("not worn instructions",
  116. true, false);
  117. mNoModifyInstructions = getChild<LLTextBox>("no modify instructions",
  118. true, false);
  119. mTitle = getChild<LLTextBox>("title", true, false);
  120. mTitleNoModify = getChild<LLTextBox>("title_no_modify", true, false);
  121. mTitleNotWorn = getChild<LLTextBox>("title_not_worn", true, false);
  122. mTitleLoading = getChild<LLTextBox>("title_loading", true, false);
  123. mPath = getChild<LLTextBox>("path", true, false);
  124. mButtonImport = getChild<LLButton>("import", true, false);
  125. if (mButtonImport)
  126. {
  127. mButtonImport->setClickedCallback(onBtnImport, this);
  128. }
  129. mButtonCreateNew = getChild<LLButton>("Create New", true, false);
  130. if (mButtonCreateNew)
  131. {
  132. mButtonCreateNew->setClickedCallback(onBtnCreateNew, this);
  133. }
  134. // If PG, cannot take off underclothing or shirt
  135. mCanTakeOff = LLWearableType::getAssetType(mType) ==
  136. LLAssetType::AT_CLOTHING;
  137. #if LL_TEEN_WERABLE_RESTRICTIONS
  138. mCanTakeOff &= !(gAgent.isTeen() &&
  139. (mType == LLWearableType::WT_UNDERSHIRT ||
  140. mType == LLWearableType::WT_UNDERPANTS));
  141. #endif
  142. mButtonTakeOff = getChild<LLButton>("Take Off", true, false);
  143. if (mButtonTakeOff)
  144. {
  145. mButtonTakeOff->setVisible(mCanTakeOff);
  146. mButtonTakeOff->setClickedCallback(onBtnTakeOff, this);
  147. }
  148. mButtonSave = getChild<LLButton>("Save", true, false);
  149. if (mButtonSave)
  150. {
  151. mButtonSave->setClickedCallback(onBtnSave, this);
  152. }
  153. mButtonSaveAs = getChild<LLButton>("Save As", true, false);
  154. if (mButtonSaveAs)
  155. {
  156. mButtonSaveAs->setClickedCallback(onBtnSaveAs, this);
  157. }
  158. mButtonRevert = getChild<LLButton>("Revert", true, false);
  159. if (mButtonRevert)
  160. {
  161. mButtonRevert->setClickedCallback(onBtnRevert, this);
  162. }
  163. mSexRadio = getChild<LLUICtrl>("sex radio", true, false);
  164. if (mSexRadio)
  165. {
  166. mSexRadio->setCommitCallback(onCommitSexChange);
  167. mSexRadio->setCallbackUserData(this);
  168. }
  169. return true;
  170. }
  171. LLPanelEditWearable::~LLPanelEditWearable()
  172. {
  173. std::for_each(mSubpartList.begin(), mSubpartList.end(),
  174. DeletePairedPointer());
  175. mSubpartList.clear();
  176. // Clear colorswatch commit callbacks that point to this object.
  177. for (std::map<std::string, S32>::iterator iter = mColorList.begin();
  178. iter != mColorList.end(); ++iter)
  179. {
  180. childSetCommitCallback(iter->first.c_str(), NULL, NULL);
  181. }
  182. }
  183. void LLPanelEditWearable::addSubpart(const std::string& name, ESubpart id,
  184. LLSubpart* part)
  185. {
  186. if (!name.empty())
  187. {
  188. childSetAction(name.c_str(), &LLPanelEditWearable::onBtnSubpart,
  189. (void*)id);
  190. part->mButtonName = name;
  191. }
  192. mSubpartList[id] = part;
  193. }
  194. //static
  195. void LLPanelEditWearable::onBtnSubpart(void* userdata)
  196. {
  197. if (!gFloaterCustomizep) return;
  198. LLPanelEditWearable* self = gFloaterCustomizep->getCurrentWearablePanel();
  199. if (!self) return;
  200. ESubpart subpart = (ESubpart) (intptr_t)userdata;
  201. self->setSubpart(subpart);
  202. }
  203. void LLPanelEditWearable::setSubpart(ESubpart subpart)
  204. {
  205. mCurrentSubpart = subpart;
  206. for (std::map<ESubpart, LLSubpart*>::iterator iter = mSubpartList.begin();
  207. iter != mSubpartList.end(); ++iter)
  208. {
  209. LLButton* btnp = getChild<LLButton>(iter->second->mButtonName.c_str(),
  210. true, false);
  211. if (btnp)
  212. {
  213. btnp->setToggleState(subpart == iter->first);
  214. }
  215. }
  216. LLSubpart* partp = get_ptr_in_map(mSubpartList, (ESubpart)subpart);
  217. if (partp && isAgentAvatarValid())
  218. {
  219. // Update the thumbnails we display
  220. LLFloaterCustomize::param_map sorted_params;
  221. ESex avatar_sex = gAgentAvatarp->getSex();
  222. LLViewerInventoryItem* itemp =
  223. gAgentWearables.getWearableInventoryItem(mType, mLayer);
  224. U32 perm_mask = 0x0;
  225. bool is_complete = false;
  226. if (itemp)
  227. {
  228. perm_mask = itemp->getPermissions().getMaskOwner();
  229. is_complete = itemp->isFinished();
  230. if (!is_complete)
  231. {
  232. // Trigger a force-fetching. HB
  233. itemp->fetchFromServer();
  234. }
  235. }
  236. setUIPermissions(perm_mask, is_complete);
  237. bool editable = (perm_mask & PERM_MODIFY) && is_complete;
  238. std::string param_name;
  239. for (LLViewerVisualParam* prmp =
  240. (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam();
  241. prmp;
  242. prmp = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam())
  243. {
  244. if (!prmp || prmp->getID() == -1 || !prmp->isTweakable() ||
  245. prmp->getEditGroup() != partp->mEditGroup ||
  246. !(prmp->getSex() & avatar_sex))
  247. {
  248. continue;
  249. }
  250. // Exclude wrinkles since the baking code was removed for them...
  251. // We still allow them for the skin (face wrinkles) in OpenSim
  252. // since they can still render in non-SSB grids (the Cool VL Viewer
  253. // does allow to bake them).
  254. param_name = prmp->getName();
  255. LLStringUtil::toLower(param_name);
  256. if (param_name.find("wrinkles") != std::string::npos &&
  257. (!LLTexLayerSet::sAllowFaceWrinkles || prmp->getID() != 163))
  258. {
  259. continue;
  260. }
  261. // Check for duplicates
  262. llassert(sorted_params.find(-prmp->getDisplayOrder()) ==
  263. sorted_params.end());
  264. // Negative getDisplayOrder() to make lowest order the highest
  265. // priority
  266. sorted_params.emplace(-prmp->getDisplayOrder(),
  267. LLFloaterCustomize::editable_param(editable,
  268. prmp));
  269. }
  270. LLJoint* jointp = gAgentAvatarp->getJoint(partp->mTargetJointKey);
  271. gFloaterCustomizep->generateVisualParamHints(this, NULL, sorted_params,
  272. mWearable,
  273. partp->mVisualHint,
  274. jointp);
  275. gFloaterCustomizep->updateScrollingPanelUI();
  276. // Update the camera
  277. gMorphViewp->setCameraTargetJoint(jointp);
  278. gMorphViewp->setCameraTargetOffset(partp->mTargetOffset);
  279. gMorphViewp->setCameraOffset(partp->mCameraOffset);
  280. if (gSavedSettings.getBool("AppearanceCameraMovement"))
  281. {
  282. gAgent.setFocusOnAvatar(false, gAgent.getCameraAnimating());
  283. gMorphViewp->updateCamera();
  284. }
  285. }
  286. }
  287. //static
  288. void LLPanelEditWearable::onBtnTakeOff(void* userdata)
  289. {
  290. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  291. if (self && gAgentWearables.getViewerWearable(self->mType, self->mLayer))
  292. {
  293. gAgentWearables.removeWearable(self->mType, false, self->mLayer);
  294. }
  295. }
  296. //static
  297. void LLPanelEditWearable::onBtnSave(void* userdata)
  298. {
  299. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  300. if (!self) return;
  301. gAgentWearables.saveWearable(self->mType, self->mLayer);
  302. }
  303. //static
  304. void LLPanelEditWearable::onBtnSaveAs(void* userdata)
  305. {
  306. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  307. if (!self) return;
  308. LLViewerWearable* wearable;
  309. wearable = gAgentWearables.getViewerWearable(self->mType, self->mLayer);
  310. if (wearable)
  311. {
  312. LLWearableSaveAsDialog* save_as_dialog;
  313. save_as_dialog = new LLWearableSaveAsDialog(wearable->getName(),
  314. onSaveAsCommit, self);
  315. save_as_dialog->startModal();
  316. // LLWearableSaveAsDialog deletes itself.
  317. }
  318. }
  319. //static
  320. void LLPanelEditWearable::onSaveAsCommit(LLWearableSaveAsDialog* save_as_dialog,
  321. void* userdata)
  322. {
  323. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  324. if (self && isAgentAvatarValid())
  325. {
  326. gAgentWearables.saveWearableAs(self->mType, self->mLayer,
  327. save_as_dialog->getItemName());
  328. }
  329. }
  330. //static
  331. void LLPanelEditWearable::onBtnRevert(void* userdata)
  332. {
  333. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  334. if (!self) return;
  335. gAgentWearables.revertWearable(self->mType, self->mLayer);
  336. }
  337. //static
  338. void LLPanelEditWearable::onBtnCreateNew(void* userdata)
  339. {
  340. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  341. if (self && isAgentAvatarValid())
  342. {
  343. // Create a new wearable in the default folder for the wearable's asset
  344. // type.
  345. LLViewerWearable* wearable =
  346. LLWearableList::getInstance()->createNewWearable(self->mType,
  347. gAgentAvatarp);
  348. LLAssetType::EType asset_type = wearable->getAssetType();
  349. // Regular UI, items get created in normal folder
  350. LLUUID folder_id =
  351. gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type));
  352. LLPointer<LLInventoryCallback> cb = new LLWearOnAvatarCallback(false);
  353. create_inventory_item(folder_id, wearable->getTransactionID(),
  354. wearable->getName(), wearable->getDescription(),
  355. asset_type, LLInventoryType::IT_WEARABLE,
  356. (U8)wearable->getType(),
  357. wearable->getPermissions().getMaskNextOwner(),
  358. cb);
  359. }
  360. }
  361. bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te)
  362. {
  363. if (isAgentAvatarValid() &&
  364. gAgentWearables.getViewerWearable(mType, getWearableIndex()))
  365. {
  366. const LLTextureEntry* current_te = gAgentAvatarp->getTE(te);
  367. return (current_te && current_te->getID() == IMG_INVISIBLE);
  368. }
  369. return false;
  370. }
  371. void LLPanelEditWearable::addInvisibilityCheckbox(ETextureIndex te,
  372. const std::string& name)
  373. {
  374. childSetCommitCallback(name.c_str(), onInvisibilityCommit, this);
  375. mInvisibilityList[name] = te;
  376. }
  377. //static
  378. void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata)
  379. {
  380. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  381. LLCheckBoxCtrl* checkbox_ctrl = (LLCheckBoxCtrl*)ctrl;
  382. if (!self || !checkbox_ctrl || !self->mWearable || !isAgentAvatarValid())
  383. {
  384. return;
  385. }
  386. ETextureIndex te =
  387. (ETextureIndex)(self->mInvisibilityList[ctrl->getName()]);
  388. bool new_invis_state = checkbox_ctrl->get();
  389. if (new_invis_state)
  390. {
  391. LLLocalTextureObject* lto = self->mWearable->getLocalTextureObject(te);
  392. self->mPreviousTextureList[te] = lto->getID();
  393. LLViewerTexture* image =
  394. LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE);
  395. gAgentAvatarp->setLocalTexture(te, image, false, self->mLayer);
  396. gAgentAvatarp->wearableUpdated(self->mType, false);
  397. }
  398. else
  399. {
  400. // Try to restore previous texture, if any.
  401. LLUUID prev_id = self->mPreviousTextureList[(S32)te];
  402. if (prev_id.isNull() || prev_id == IMG_INVISIBLE)
  403. {
  404. prev_id = LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID"));
  405. }
  406. if (prev_id.notNull())
  407. {
  408. LLViewerTexture* image =
  409. LLViewerTextureManager::getFetchedTexture(prev_id);
  410. if (image)
  411. {
  412. gAgentAvatarp->setLocalTexture(te, image, false, self->mLayer);
  413. gAgentAvatarp->wearableUpdated(self->mType, false);
  414. }
  415. }
  416. }
  417. }
  418. void LLPanelEditWearable::addColorSwatch(ETextureIndex te,
  419. const std::string& name)
  420. {
  421. childSetCommitCallback(name.c_str(), LLPanelEditWearable::onColorCommit, this);
  422. mColorList[name] = te;
  423. }
  424. //static
  425. void LLPanelEditWearable::onColorCommit(LLUICtrl* ctrl, void* userdata)
  426. {
  427. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  428. LLColorSwatchCtrl* color_ctrl = (LLColorSwatchCtrl*)ctrl;
  429. if (self && color_ctrl && isAgentAvatarValid() && self->mWearable)
  430. {
  431. std::map<std::string, S32>::const_iterator cl_itr =
  432. self->mColorList.find(ctrl->getName());
  433. if (cl_itr != self->mColorList.end())
  434. {
  435. ETextureIndex te = (ETextureIndex)cl_itr->second;
  436. LLColor4 old_color = self->mWearable->getClothesColor(te);
  437. const LLColor4& new_color = color_ctrl->get();
  438. if (old_color != new_color)
  439. {
  440. // Set the new version
  441. self->mWearable->setClothesColor(te, new_color, true);
  442. #if 0
  443. gAgentAvatarp->setClothesColor(te, new_color, true);
  444. #endif
  445. LLVisualParamHint::requestHintUpdates();
  446. gAgentAvatarp->wearableUpdated(self->mType, false);
  447. }
  448. }
  449. }
  450. }
  451. void LLPanelEditWearable::initPreviousTextureList()
  452. {
  453. initPreviousTextureListEntry(TEX_LOWER_ALPHA);
  454. initPreviousTextureListEntry(TEX_UPPER_ALPHA);
  455. initPreviousTextureListEntry(TEX_HEAD_ALPHA);
  456. initPreviousTextureListEntry(TEX_EYES_ALPHA);
  457. initPreviousTextureListEntry(TEX_LOWER_ALPHA);
  458. }
  459. void LLPanelEditWearable::initPreviousTextureListEntry(ETextureIndex te)
  460. {
  461. if (mWearable)
  462. {
  463. LLUUID id;
  464. LLLocalTextureObject* lto = mWearable->getLocalTextureObject(te);
  465. if (lto)
  466. {
  467. id = lto->getID();
  468. }
  469. mPreviousTextureList[te] = id;
  470. }
  471. }
  472. void LLPanelEditWearable::addTextureDropTarget(ETextureIndex te,
  473. const std::string& name,
  474. const LLUUID& default_image_id,
  475. bool allow_no_texture)
  476. {
  477. childSetCommitCallback(name.c_str(), onTextureCommit, this);
  478. LLTextureCtrl* tex_ctrl = getChild<LLTextureCtrl>(name.c_str(), true,
  479. false);
  480. if (tex_ctrl)
  481. {
  482. tex_ctrl->setDefaultImageAssetID(default_image_id);
  483. tex_ctrl->setAllowNoTexture(allow_no_texture);
  484. // Do not allow (no copy) or (no transfer) textures to be selected.
  485. tex_ctrl->setImmediateFilterPermMask(PERM_NONE);
  486. tex_ctrl->setNonImmediateFilterPermMask(PERM_NONE);
  487. }
  488. mTextureList[name] = te;
  489. if (mType == LLWearableType::WT_ALPHA)
  490. {
  491. initPreviousTextureListEntry(te);
  492. }
  493. }
  494. //static
  495. void LLPanelEditWearable::onTextureCommit(LLUICtrl* ctrl, void* userdata)
  496. {
  497. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  498. LLTextureCtrl* tex_ctrl = (LLTextureCtrl*)ctrl;
  499. if (self && ctrl && isAgentAvatarValid())
  500. {
  501. ETextureIndex te =
  502. (ETextureIndex)(self->mTextureList[ctrl->getName()]);
  503. // Set the new version
  504. LLViewerTexture* image =
  505. LLViewerTextureManager::getFetchedTexture(tex_ctrl->getImageAssetID());
  506. if (image->getID().isNull() || image->getID() == IMG_DEFAULT)
  507. {
  508. image =
  509. LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
  510. }
  511. self->mTextureList[ctrl->getName()] = te;
  512. if (self->mWearable)
  513. {
  514. gAgentAvatarp->setLocalTexture(te, image, false, self->mLayer);
  515. LLVisualParamHint::requestHintUpdates();
  516. gAgentAvatarp->wearableUpdated(self->mType, false);
  517. }
  518. if (self->mType == LLWearableType::WT_ALPHA &&
  519. image->getID() != IMG_INVISIBLE)
  520. {
  521. self->mPreviousTextureList[te] = image->getID();
  522. }
  523. }
  524. }
  525. ESubpart LLPanelEditWearable::getDefaultSubpart()
  526. {
  527. switch (mType)
  528. {
  529. case LLWearableType::WT_SHAPE:
  530. return SUBPART_SHAPE_WHOLE;
  531. case LLWearableType::WT_SKIN:
  532. return SUBPART_SKIN_COLOR;
  533. case LLWearableType::WT_HAIR:
  534. return SUBPART_HAIR_COLOR;
  535. case LLWearableType::WT_EYES:
  536. return SUBPART_EYES;
  537. case LLWearableType::WT_SHIRT:
  538. return SUBPART_SHIRT;
  539. case LLWearableType::WT_PANTS:
  540. return SUBPART_PANTS;
  541. case LLWearableType::WT_SHOES:
  542. return SUBPART_SHOES;
  543. case LLWearableType::WT_SOCKS:
  544. return SUBPART_SOCKS;
  545. case LLWearableType::WT_JACKET:
  546. return SUBPART_JACKET;
  547. case LLWearableType::WT_GLOVES:
  548. return SUBPART_GLOVES;
  549. case LLWearableType::WT_UNDERSHIRT:
  550. return SUBPART_UNDERSHIRT;
  551. case LLWearableType::WT_UNDERPANTS:
  552. return SUBPART_UNDERPANTS;
  553. case LLWearableType::WT_SKIRT:
  554. return SUBPART_SKIRT;
  555. case LLWearableType::WT_ALPHA:
  556. return SUBPART_ALPHA;
  557. case LLWearableType::WT_TATTOO:
  558. return SUBPART_TATTOO;
  559. case LLWearableType::WT_UNIVERSAL:
  560. return SUBPART_UNIVERSAL;
  561. case LLWearableType::WT_PHYSICS:
  562. return SUBPART_PHYSICS_BELLY_UPDOWN;
  563. default:
  564. llwarns << "Unknown sub-part type: " << mType << llendl;
  565. llassert(false);
  566. return SUBPART_SHAPE_WHOLE;
  567. }
  568. }
  569. void LLPanelEditWearable::draw()
  570. {
  571. if (!gFloaterCustomizep || gFloaterCustomizep->isMinimized() ||
  572. !isAgentAvatarValid())
  573. {
  574. return;
  575. }
  576. bool has_wearable = mWearable != NULL;
  577. bool is_dirty = isDirty();
  578. bool is_modifiable = false;
  579. bool is_copyable = false;
  580. bool is_complete = false;
  581. LLViewerInventoryItem* itemp = NULL;
  582. if (has_wearable)
  583. {
  584. itemp = gAgentWearables.getWearableInventoryItem(mType, mLayer);
  585. if (itemp)
  586. {
  587. const LLPermissions& perm = itemp->getPermissions();
  588. is_modifiable = perm.allowModifyBy(gAgentID, gAgent.getGroupID());
  589. is_copyable = perm.allowCopyBy(gAgentID, gAgent.getGroupID());
  590. is_complete = itemp->isFinished();
  591. }
  592. }
  593. setMaxLayers();
  594. if (mButtonSave)
  595. {
  596. mButtonSave->setEnabled(is_modifiable && is_complete && has_wearable &&
  597. is_dirty);
  598. mButtonSave->setVisible(has_wearable || !mButtonCreateNew);
  599. }
  600. if (mButtonSaveAs)
  601. {
  602. mButtonSaveAs->setEnabled(is_copyable && is_complete && has_wearable);
  603. mButtonSaveAs->setVisible(has_wearable || !mButtonCreateNew);
  604. }
  605. if (mButtonRevert)
  606. {
  607. mButtonRevert->setEnabled(has_wearable && is_dirty);
  608. mButtonRevert->setVisible(has_wearable || !mButtonCreateNew);
  609. }
  610. if (mButtonTakeOff)
  611. {
  612. mButtonTakeOff->setEnabled(has_wearable);
  613. mButtonTakeOff->setVisible(mCanTakeOff && has_wearable);
  614. }
  615. if (mButtonCreateNew)
  616. {
  617. mButtonCreateNew->setVisible(!has_wearable);
  618. }
  619. if (mNotWornInstructions)
  620. {
  621. mNotWornInstructions->setVisible(!has_wearable);
  622. }
  623. if (mNoModifyInstructions)
  624. {
  625. mNoModifyInstructions->setVisible(has_wearable && !is_modifiable);
  626. }
  627. for (std::map<ESubpart, LLSubpart*>::iterator iter = mSubpartList.begin(),
  628. end = mSubpartList.end();
  629. iter != end; ++iter)
  630. {
  631. std::string btn_name = iter->second->mButtonName;
  632. LLButton* button = getChild<LLButton>(btn_name.c_str(), true, false);
  633. if (button)
  634. {
  635. button->setVisible(has_wearable);
  636. if (has_wearable && is_complete && is_modifiable)
  637. {
  638. button->setEnabled(iter->second->mSex &
  639. gAgentAvatarp->getSex());
  640. }
  641. else
  642. {
  643. button->setEnabled(false);
  644. }
  645. }
  646. }
  647. if (mLockIcon)
  648. {
  649. mLockIcon->setVisible(!is_modifiable);
  650. }
  651. if (mTitle)
  652. {
  653. mTitle->setVisible(false);
  654. }
  655. if (mTitleNoModify)
  656. {
  657. mTitleNoModify->setVisible(false);
  658. }
  659. if (mTitleNotWorn)
  660. {
  661. mTitleNotWorn->setVisible(false);
  662. }
  663. if (mTitleLoading)
  664. {
  665. mTitleLoading->setVisible(false);
  666. }
  667. if (mPath)
  668. {
  669. mPath->setVisible(false);
  670. }
  671. if (has_wearable && !is_modifiable)
  672. {
  673. if (mTitleNoModify)
  674. {
  675. mTitleNoModify->setVisible(true);
  676. // *TODO:Translate
  677. mTitleNoModify->setTextArg("[DESC]", itemp ? itemp->getName()
  678. : mWearable->getName());
  679. }
  680. hideTextureControls();
  681. }
  682. else if (has_wearable && !is_complete)
  683. {
  684. if (mTitleLoading)
  685. {
  686. mTitleLoading->setVisible(true);
  687. // *TODO:Translate
  688. mTitleLoading->setTextArg("[DESC]",
  689. LLWearableType::getTypeLabel(mType));
  690. }
  691. if (mPath)
  692. {
  693. std::string path;
  694. const LLUUID& item_id = gAgentWearables.getWearableItemID(mType,
  695. mLayer);
  696. gInventory.appendPath(item_id, path);
  697. mPath->setVisible(true);
  698. mPath->setTextArg("[PATH]", path);
  699. }
  700. hideTextureControls();
  701. }
  702. else if (has_wearable && is_modifiable)
  703. {
  704. if (mTitle)
  705. {
  706. mTitle->setVisible(true);
  707. mTitle->setTextArg("[DESC]", itemp ? itemp->getName()
  708. : mWearable->getName());
  709. }
  710. if (mPath)
  711. {
  712. std::string path;
  713. const LLUUID& item_id = gAgentWearables.getWearableItemID(mType,
  714. mLayer);
  715. gInventory.appendPath(item_id, path);
  716. mPath->setVisible(true);
  717. mPath->setTextArg("[PATH]", path);
  718. }
  719. for (std::map<std::string, S32>::iterator iter = mTextureList.begin(),
  720. end = mTextureList.end();
  721. iter != end; ++iter)
  722. {
  723. std::string name = iter->first;
  724. LLTextureCtrl* tex_ctrl = getChild<LLTextureCtrl>(name.c_str(),
  725. true, false);
  726. if (tex_ctrl)
  727. {
  728. tex_ctrl->setVisible(is_copyable && is_modifiable &&
  729. is_complete);
  730. ETextureIndex te = (ETextureIndex)iter->second;
  731. LLLocalTextureObject* lto =
  732. mWearable->getLocalTextureObject(te);
  733. LLUUID new_id;
  734. if (lto && lto->getID() != IMG_DEFAULT_AVATAR)
  735. {
  736. new_id = lto->getID();
  737. }
  738. if (tex_ctrl->getImageAssetID() != new_id)
  739. {
  740. // Texture has changed, close the floater to avoid
  741. // DEV-22461
  742. tex_ctrl->closeFloater();
  743. }
  744. tex_ctrl->setImageAssetID(new_id);
  745. }
  746. }
  747. for (std::map<std::string, S32>::iterator iter = mColorList.begin(),
  748. end = mColorList.end();
  749. iter != end; ++iter)
  750. {
  751. std::string name = iter->first;
  752. LLColorSwatchCtrl* ctrl = getChild<LLColorSwatchCtrl>(name.c_str(),
  753. true, false);
  754. if (ctrl)
  755. {
  756. ctrl->setVisible(is_modifiable && is_complete);
  757. ctrl->setEnabled(is_modifiable && is_complete);
  758. ETextureIndex te = (ETextureIndex)iter->second;
  759. ctrl->set(mWearable->getClothesColor(te));
  760. }
  761. }
  762. for (std::map<std::string, S32>::iterator
  763. iter = mInvisibilityList.begin(),
  764. end = mInvisibilityList.end();
  765. iter != end; ++iter)
  766. {
  767. std::string name = iter->first;
  768. LLCheckBoxCtrl* ctrl = getChild<LLCheckBoxCtrl>(name.c_str(), true,
  769. false);
  770. if (ctrl)
  771. {
  772. ctrl->setVisible(is_copyable && is_modifiable && is_complete);
  773. ctrl->setEnabled(is_copyable && is_modifiable && is_complete);
  774. ETextureIndex te = (ETextureIndex)iter->second;
  775. ctrl->set(!gAgentAvatarp->isTextureVisible(te, mWearable));
  776. }
  777. }
  778. }
  779. else
  780. {
  781. if (mTitleNotWorn)
  782. {
  783. mTitleNotWorn->setVisible(true);
  784. // *TODO:Translate
  785. mTitleNotWorn->setTextArg("[DESC]",
  786. LLWearableType::getTypeLabel(mType));
  787. }
  788. hideTextureControls();
  789. }
  790. #if 0
  791. if (mWearableIcon)
  792. {
  793. mWearableIcon->setVisible(has_wearable);
  794. }
  795. #endif
  796. LLPanel::draw();
  797. }
  798. void LLPanelEditWearable::hideTextureControls()
  799. {
  800. for (std::map<std::string, S32>::iterator iter = mTextureList.begin(),
  801. end = mTextureList.end();
  802. iter != end; ++iter)
  803. {
  804. childSetVisible(iter->first.c_str(), false);
  805. }
  806. for (std::map<std::string, S32>::iterator iter = mColorList.begin(),
  807. end = mColorList.end();
  808. iter != end; ++iter)
  809. {
  810. childSetVisible(iter->first.c_str(), false);
  811. }
  812. for (std::map<std::string, S32>::iterator iter = mInvisibilityList.begin(),
  813. end = mInvisibilityList.end();
  814. iter != end; ++iter)
  815. {
  816. childSetVisible(iter->first.c_str(), false);
  817. }
  818. }
  819. void LLPanelEditWearable::setMaxLayers()
  820. {
  821. if (mSpinLayer)
  822. {
  823. mSpinLayer->setMaxValue((F32)gAgentWearables.getWearableCount(mType));
  824. }
  825. }
  826. void LLPanelEditWearable::setWearable(LLViewerWearable* wearable,
  827. U32 perm_mask, bool is_complete)
  828. {
  829. mWearable = wearable;
  830. if (wearable)
  831. {
  832. mLayer = 0;
  833. gAgentWearables.getWearableIndex(wearable, mLayer);
  834. if (mSpinLayer)
  835. {
  836. setMaxLayers();
  837. mSpinLayer->set((F32)mLayer);
  838. }
  839. if (mType == LLWearableType::WT_ALPHA)
  840. {
  841. initPreviousTextureList();
  842. }
  843. }
  844. setUIPermissions(perm_mask, is_complete);
  845. }
  846. void LLPanelEditWearable::switchToDefaultSubpart()
  847. {
  848. setSubpart(getDefaultSubpart());
  849. }
  850. void LLPanelEditWearable::setVisible(bool visible)
  851. {
  852. LLPanel::setVisible(visible);
  853. if (!visible)
  854. {
  855. for (std::map<std::string, S32>::iterator iter = mColorList.begin(),
  856. end = mColorList.end();
  857. iter != end; ++iter)
  858. {
  859. // This forces any open color pickers to cancel their selection
  860. childSetEnabled(iter->first.c_str(), false);
  861. }
  862. }
  863. }
  864. bool LLPanelEditWearable::isDirty() const
  865. {
  866. LLViewerWearable* wearable = gAgentWearables.getViewerWearable(mType,
  867. mLayer);
  868. return wearable && wearable->isDirty();
  869. }
  870. //static
  871. void LLPanelEditWearable::onCommitSexChange(LLUICtrl*, void* userdata)
  872. {
  873. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  874. if (!self || !self->mWearable) return;
  875. if (!isAgentAvatarValid() || !gFloaterCustomizep)
  876. {
  877. return;
  878. }
  879. if (!gAgentWearables.isWearableModifiable(self->mType, self->mLayer))
  880. {
  881. return;
  882. }
  883. ESex new_sex = gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE;
  884. LLViewerVisualParam* param =
  885. (LLViewerVisualParam*)gAgentAvatarp->getVisualParam("male");
  886. if (!param)
  887. {
  888. return;
  889. }
  890. self->mWearable->setVisualParamWeight(param->getID(), new_sex == SEX_MALE,
  891. true);
  892. self->mWearable->writeToAvatar(gAgentAvatarp);
  893. gAgentAvatarp->updateSexDependentLayerSets(true);
  894. gAgentAvatarp->updateVisualParams();
  895. gFloaterCustomizep->clearScrollingPanelList();
  896. // Assumes that we're in the "Shape" Panel.
  897. self->setSubpart(SUBPART_SHAPE_WHOLE);
  898. }
  899. // Helper for the callback below
  900. void error_message(std::string message)
  901. {
  902. LLSD args;
  903. args["MESSAGE"] = message;
  904. gNotifications.add("GenericAlert", args);
  905. }
  906. //static
  907. void LLPanelEditWearable::importCallback(HBFileSelector::ELoadFilter type,
  908. std::string& filename,
  909. void* userdata)
  910. {
  911. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  912. if (!gFloaterCustomizep || !self || !self->mWearable || filename.empty() ||
  913. !isAgentAvatarValid())
  914. {
  915. return;
  916. }
  917. llinfos << "Selected import file: " << filename << llendl;
  918. LLXmlTree xml_tree;
  919. if (!xml_tree.parseFile(filename, false))
  920. {
  921. error_message("Can't read the xml file, aborting.");
  922. return;
  923. }
  924. // Check the file format and version
  925. LLXmlTreeNode* root = xml_tree.getRoot();
  926. if (!root)
  927. {
  928. error_message("No root node found in xml file, aborting.");
  929. return;
  930. }
  931. if (!root->hasName("linden_genepool"))
  932. {
  933. error_message("Not an avatar dump, aborting.");
  934. return;
  935. }
  936. std::string version;
  937. static LLStdStringHandle version_string =
  938. LLXmlTree::addAttributeString("version");
  939. if (!root->getFastAttributeString(version_string, version) ||
  940. version != "1.0")
  941. {
  942. error_message("Invalid or missing avatar dump version, aborting.");
  943. return;
  944. }
  945. LLXmlTreeNode* node = root->getChildByName("archetype");
  946. if (!node)
  947. {
  948. error_message("Missing archetype node in avatar dump, aborting.");
  949. return;
  950. }
  951. // Read the file and place the params' id and value in a map
  952. S32 id;
  953. F32 value;
  954. static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
  955. static LLStdStringHandle value_string =
  956. LLXmlTree::addAttributeString("value");
  957. std::map<S32, F32> params_map;
  958. for (LLXmlTreeNode* child = node->getChildByName("param"); child;
  959. child = node->getNextNamedChild())
  960. {
  961. if (child->getFastAttributeS32(id_string, id) &&
  962. child->getFastAttributeF32(value_string, value))
  963. {
  964. params_map.emplace(id, value);
  965. }
  966. }
  967. // Now set the visual params that correspond to our type
  968. bool sex_changed = false;
  969. std::map<S32, F32>::const_iterator it;
  970. std::map<S32, F32>::const_iterator end = params_map.end();
  971. for (LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param;
  972. param = gAgentAvatarp->getNextVisualParam())
  973. {
  974. LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
  975. if (viewer_param->getWearableType() == self->mType &&
  976. viewer_param->isTweakable())
  977. {
  978. id = viewer_param->getID();
  979. it = params_map.find(id);
  980. if (it != end)
  981. {
  982. value = it->second;
  983. if (viewer_param->getName() == "male")
  984. {
  985. ESex sex = gSavedSettings.getU32("AvatarSex") ? SEX_MALE
  986. : SEX_FEMALE;
  987. ESex new_sex = value > 0.5f ? SEX_MALE : SEX_FEMALE;
  988. if (new_sex != sex)
  989. {
  990. gSavedSettings.setU32("AvatarSex",
  991. new_sex == SEX_MALE);
  992. sex_changed = true;
  993. }
  994. }
  995. llinfos << "Setting param id " << id << " to value "
  996. << value << llendl;
  997. self->mWearable->setVisualParamWeight(id, value, true);
  998. }
  999. }
  1000. }
  1001. self->mWearable->writeToAvatar(gAgentAvatarp);
  1002. if (sex_changed)
  1003. {
  1004. gAgentAvatarp->updateSexDependentLayerSets(true);
  1005. gAgentAvatarp->updateVisualParams();
  1006. gFloaterCustomizep->clearScrollingPanelList();
  1007. // Assumes that we're in the "Shape" Panel.
  1008. self->setSubpart(SUBPART_SHAPE_WHOLE);
  1009. }
  1010. else
  1011. {
  1012. gAgentAvatarp->updateVisualParams();
  1013. gFloaterCustomizep->updateScrollingPanelUI();
  1014. }
  1015. }
  1016. //static
  1017. void LLPanelEditWearable::onBtnImport(void* userdata)
  1018. {
  1019. HBFileSelector::loadFile(HBFileSelector::FFLOAD_XML, importCallback,
  1020. userdata);
  1021. }
  1022. //static
  1023. void LLPanelEditWearable::onCommitLayer(LLUICtrl*, void* userdata)
  1024. {
  1025. LLPanelEditWearable* self = (LLPanelEditWearable*)userdata;
  1026. if (!self || !self->mSpinLayer || !gFloaterCustomizep) return;
  1027. U32 index = (U32)self->mSpinLayer->get();
  1028. LLViewerWearable* wearable =
  1029. gAgentWearables.getViewerWearable(self->mType, index);
  1030. if (wearable)
  1031. {
  1032. gFloaterCustomizep->updateWearableType(self->mType, wearable);
  1033. }
  1034. else
  1035. {
  1036. self->setWearable(NULL, PERM_ALL, true);
  1037. LLFloaterCustomize::setCurrentWearableType(self->mType);
  1038. gFloaterCustomizep->updateScrollingPanelUI();
  1039. }
  1040. }
  1041. void LLPanelEditWearable::setUIPermissions(U32 perm_mask, bool is_complete)
  1042. {
  1043. bool is_copyable = (perm_mask & PERM_COPY) != 0;
  1044. bool is_modifiable = (perm_mask & PERM_MODIFY) != 0;
  1045. if (mButtonImport)
  1046. {
  1047. mButtonImport->setEnabled(is_modifiable && is_complete);
  1048. }
  1049. if (mButtonSave)
  1050. {
  1051. mButtonSave->setEnabled(is_modifiable && is_complete);
  1052. }
  1053. if (mButtonSaveAs)
  1054. {
  1055. mButtonSaveAs->setEnabled(is_copyable && is_complete);
  1056. }
  1057. if (mSexRadio)
  1058. {
  1059. mSexRadio->setEnabled(is_modifiable && is_complete);
  1060. }
  1061. for (std::map<std::string, S32>::iterator iter = mTextureList.begin(),
  1062. end = mTextureList.end();
  1063. iter != end; ++iter)
  1064. {
  1065. childSetVisible(iter->first.c_str(),
  1066. is_copyable && is_modifiable && is_complete);
  1067. }
  1068. for (std::map<std::string, S32>::iterator iter = mColorList.begin(),
  1069. end = mColorList.end();
  1070. iter != end; ++iter)
  1071. {
  1072. childSetVisible(iter->first.c_str(), is_modifiable && is_complete);
  1073. }
  1074. for (std::map<std::string, S32>::iterator iter = mInvisibilityList.begin(),
  1075. end = mInvisibilityList.end();
  1076. iter != end; ++iter)
  1077. {
  1078. childSetVisible(iter->first.c_str(),
  1079. is_copyable && is_modifiable && is_complete);
  1080. }
  1081. }
  1082. ////////////////////////////////////////////////////////////////////////////
  1083. LLWearableSaveAsDialog::LLWearableSaveAsDialog(const std::string& desc,
  1084. void (*commit_cb)(LLWearableSaveAsDialog*,
  1085. void*),
  1086. void* userdata)
  1087. : LLModalDialog(LLStringUtil::null, 240, 100),
  1088. mCommitCallback(commit_cb),
  1089. mCallbackUserData(userdata)
  1090. {
  1091. LLUICtrlFactory::getInstance()->buildFloater(this,
  1092. "floater_wearable_save_as.xml");
  1093. childSetAction("Save", LLWearableSaveAsDialog::onSave, this);
  1094. childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this);
  1095. childSetTextArg("name ed", "[DESC]", desc);
  1096. }
  1097. //virtual
  1098. void LLWearableSaveAsDialog::startModal()
  1099. {
  1100. LLModalDialog::startModal();
  1101. LLLineEditor* edit = getChild<LLLineEditor>("name ed", true, false);
  1102. if (edit)
  1103. {
  1104. edit->setFocus(true);
  1105. edit->selectAll();
  1106. }
  1107. }
  1108. //static
  1109. void LLWearableSaveAsDialog::onSave(void* userdata)
  1110. {
  1111. LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*)userdata;
  1112. self->mItemName = self->childGetValue("name ed").asString();
  1113. LLStringUtil::trim(self->mItemName);
  1114. if (!self->mItemName.empty())
  1115. {
  1116. if (self->mCommitCallback)
  1117. {
  1118. self->mCommitCallback(self, self->mCallbackUserData);
  1119. }
  1120. self->close(); // Destroys this object
  1121. }
  1122. }
  1123. //static
  1124. void LLWearableSaveAsDialog::onCancel(void* userdata)
  1125. {
  1126. LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*)userdata;
  1127. self->close(); // Destroys this object
  1128. }