llscrollingpanelparam.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /**
  2. * @file llscrollingpanelparam.cpp
  3. * @brief the scrolling panel containing a list of visual param
  4. * panels
  5. *
  6. * $LicenseInfo:firstyear=2002&license=viewergpl$
  7. *
  8. * Copyright (c) 2002-2009, Linden Research, Inc.
  9. *
  10. * Second Life Viewer Source Code
  11. * The source code in this file ("Source Code") is provided by Linden Lab
  12. * to you under the terms of the GNU General Public License, version 2.0
  13. * ("GPL"), unless you have obtained a separate licensing agreement
  14. * ("Other License"), formally executed by you and Linden Lab. Terms of
  15. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17. *
  18. * There are special exceptions to the terms and conditions of the GPL as
  19. * it is applied to this Source Code. View the full text of the exception
  20. * in the file doc/FLOSS-exception.txt in this software distribution, or
  21. * online at
  22. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23. *
  24. * By copying, modifying or distributing this software, you acknowledge
  25. * that you have read and understood your obligations described above,
  26. * and agree to abide by those obligations.
  27. *
  28. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30. * COMPLETENESS OR PERFORMANCE.
  31. * $/LicenseInfo$
  32. */
  33. #include "llviewerprecompiledheaders.h"
  34. #include "llscrollingpanelparam.h"
  35. #include "llviewervisualparam.h"
  36. #include "lluictrlfactory.h"
  37. #include "llwearable.h"
  38. #include "llagent.h"
  39. #include "llfloatercustomize.h"
  40. #include "llpaneleditwearable.h"
  41. #include "llviewercontrol.h"
  42. #include "llviewerjointmesh.h"
  43. #include "llvisualparamhint.h"
  44. #include "llvoavatarself.h"
  45. //static
  46. S32 LLScrollingPanelParam::sUpdateDelayFrames = 0;
  47. constexpr S32 BTN_BORDER = 2;
  48. constexpr S32 PARAM_HINT_WIDTH = 128;
  49. constexpr S32 PARAM_HINT_HEIGHT = 128;
  50. constexpr S32 PARAM_HINT_LABEL_HEIGHT = 16;
  51. constexpr S32 PARAM_PANEL_WIDTH =
  52. 2 * (3 * BTN_BORDER + PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH);
  53. constexpr S32 PARAM_PANEL_HEIGHT =
  54. 2 * BTN_BORDER + PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT +
  55. 4 * LLPANEL_BORDER_WIDTH;
  56. constexpr F32 PARAM_STEP_TIME_THRESHOLD = 0.25f;
  57. LLScrollingPanelParam::LLScrollingPanelParam(LLPanelEditWearable* panel,
  58. LLViewerJointMesh* mesh,
  59. LLViewerVisualParam* param,
  60. bool allow_modify,
  61. LLWearable* wearable,
  62. LLJoint* jointp,
  63. bool use_hints)
  64. : LLScrollingPanel("LLScrollingPanelParam",
  65. LLRect(0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0)),
  66. mPanelParams(panel),
  67. mWearable(wearable),
  68. mParam(param),
  69. mAllowModify(allow_modify),
  70. mLess(NULL),
  71. mMore(NULL),
  72. mHintMin(NULL),
  73. mHintMax(NULL),
  74. mSlider(NULL),
  75. mMinParamText(NULL),
  76. mMaxParamText(NULL)
  77. {
  78. LLUICtrlFactory::getInstance()->buildPanel(this,
  79. "panel_scrolling_param.xml");
  80. // Set up the slider
  81. mSlider = getChild<LLSliderCtrl>("param slider", true, false);
  82. if (mSlider)
  83. {
  84. mSlider->setValue(weightToPercent(param->getWeight()));
  85. mSlider->setLabelArg("[DESC]", param->getDisplayName());
  86. mSlider->setEnabled(mAllowModify);
  87. mSlider->setCommitCallback(onSliderMoved);
  88. mSlider->setCallbackUserData(this);
  89. }
  90. if (use_hints)
  91. {
  92. S32 pos_x = 2 * LLPANEL_BORDER_WIDTH;
  93. S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT;
  94. F32 min_weight = param->getMinWeight();
  95. F32 max_weight = param->getMaxWeight();
  96. LLViewerVisualParam* wearable_param;
  97. if (wearable)
  98. {
  99. wearable_param =
  100. (LLViewerVisualParam*)wearable->getVisualParam(param->getID());
  101. }
  102. else
  103. {
  104. LL_DEBUGS("Appearance") << "wearable is NULL. Using viewer visualparam."
  105. << LL_ENDL;
  106. wearable_param = param;
  107. }
  108. mHintMin = new LLVisualParamHint(pos_x, pos_y,
  109. PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT,
  110. mesh, wearable_param, wearable,
  111. min_weight, jointp);
  112. pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER;
  113. mHintMax = new LLVisualParamHint(pos_x, pos_y,
  114. PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT,
  115. mesh, wearable_param, wearable,
  116. max_weight, jointp);
  117. mHintMin->setAllowsUpdates(false);
  118. mHintMax->setAllowsUpdates(false);
  119. mMinParamText = getChild<LLTextBox>("min param text", true, false);
  120. if (mMinParamText)
  121. {
  122. // *TODO::translate
  123. std::string min_name = param->getMinDisplayName();
  124. mMinParamText->setValue(min_name);
  125. }
  126. mMaxParamText = getChild<LLTextBox>("max param text", true, false);
  127. if (mMaxParamText)
  128. {
  129. // *TODO::translate
  130. std::string max_name = param->getMaxDisplayName();
  131. mMaxParamText->setValue(max_name);
  132. }
  133. mLess = getChild<LLButton>("less", true, false);
  134. if (mLess)
  135. {
  136. mLess->setMouseDownCallback(onHintMinMouseDown);
  137. mLess->setMouseUpCallback(onHintMinMouseUp);
  138. mLess->setHeldDownCallback(onHintMinHeldDown);
  139. mLess->setHeldDownDelay(PARAM_STEP_TIME_THRESHOLD);
  140. }
  141. mMore = getChild<LLButton>("more", true, false);
  142. if (mMore)
  143. {
  144. mMore->setMouseDownCallback(onHintMaxMouseDown);
  145. mMore->setMouseUpCallback(onHintMaxMouseUp);
  146. mMore->setHeldDownCallback(onHintMaxHeldDown);
  147. mMore->setHeldDownDelay(PARAM_STEP_TIME_THRESHOLD);
  148. }
  149. }
  150. else
  151. {
  152. // Kill everything that is not the slider...
  153. child_list_t to_remove;
  154. child_list_t::const_iterator it;
  155. for (it = getChildList()->begin(); it != getChildList()->end(); ++it)
  156. {
  157. if (*it != mSlider && (*it)->getName() != "panel border")
  158. {
  159. to_remove.push_back(*it);
  160. }
  161. }
  162. for (it = to_remove.begin(); it != to_remove.end(); ++it)
  163. {
  164. removeChild(*it, true);
  165. }
  166. if (mSlider)
  167. {
  168. mSlider->translate(0, PARAM_HINT_HEIGHT);
  169. }
  170. reshape(getRect().getWidth(),
  171. getRect().getHeight() - PARAM_HINT_HEIGHT);
  172. }
  173. setVisible(false);
  174. setBorderVisible(false);
  175. }
  176. LLScrollingPanelParam::~LLScrollingPanelParam()
  177. {
  178. mHintMin = NULL;
  179. mHintMax = NULL;
  180. }
  181. void LLScrollingPanelParam::updatePanel(bool allow_modify)
  182. {
  183. if (mWearable != mPanelParams->getWearable())
  184. {
  185. LL_DEBUGS("Appearance") << "Wearable change detected for parameter "
  186. << mParam->getID() << LL_ENDL;
  187. // The wearable changed...
  188. mWearable = mPanelParams->getWearable();
  189. if (mWearable && mHintMin)
  190. {
  191. LL_DEBUGS("Appearance") << "Updating visual hints for parameter "
  192. << mParam->getID() << LL_ENDL;
  193. LLViewerVisualParam* wearable_param;
  194. wearable_param = (LLViewerVisualParam*)mWearable->getVisualParam(mParam->getID());
  195. mHintMin->setWearable(mWearable, wearable_param);
  196. mHintMax->setWearable(mWearable, wearable_param);
  197. LLVisualParamHint::requestHintUpdates(mHintMin, mHintMax);
  198. }
  199. }
  200. if (!mWearable)
  201. {
  202. setVisible(false);
  203. // not editing a wearable just now, no update necessary
  204. return;
  205. }
  206. if (mSlider)
  207. {
  208. F32 current_weight = mWearable->getVisualParamWeight(mParam->getID());
  209. mSlider->setValue(weightToPercent(current_weight));
  210. }
  211. if (mHintMin)
  212. {
  213. mHintMin->requestUpdate(sUpdateDelayFrames++);
  214. mHintMax->requestUpdate(sUpdateDelayFrames++);
  215. }
  216. mAllowModify = allow_modify;
  217. if (mSlider)
  218. {
  219. mSlider->setEnabled(mAllowModify);
  220. }
  221. if (mLess)
  222. {
  223. mLess->setEnabled(mAllowModify);
  224. }
  225. if (mMore)
  226. {
  227. mMore->setEnabled(mAllowModify);
  228. }
  229. }
  230. void LLScrollingPanelParam::setVisible(bool visible)
  231. {
  232. if (getVisible() != visible)
  233. {
  234. LLPanel::setVisible(visible);
  235. setBorderVisible(false);
  236. setMouseOpaque(visible);
  237. if (mHintMin)
  238. {
  239. mHintMin->setAllowsUpdates(visible);
  240. mHintMax->setAllowsUpdates(visible);
  241. if (visible)
  242. {
  243. mHintMin->setUpdateDelayFrames(sUpdateDelayFrames++);
  244. mHintMax->setUpdateDelayFrames(sUpdateDelayFrames++);
  245. }
  246. }
  247. }
  248. }
  249. void LLScrollingPanelParam::draw()
  250. {
  251. if (!mWearable || !gFloaterCustomizep || gFloaterCustomizep->isMinimized())
  252. {
  253. return;
  254. }
  255. if (mLess)
  256. {
  257. mLess->setVisible(mHintMin ? mHintMin->getVisible() : false);
  258. }
  259. if (mMore)
  260. {
  261. mMore->setVisible(mHintMax ? mHintMax->getVisible() : false);
  262. }
  263. // Draw all the children except for the labels
  264. if (mMinParamText)
  265. {
  266. mMinParamText->setVisible(false);
  267. }
  268. if (mMaxParamText)
  269. {
  270. mMaxParamText->setVisible(false);
  271. }
  272. LLPanel::draw();
  273. // Draw the hints over the "less" and "more" buttons.
  274. if (mHintMin)
  275. {
  276. gGL.pushUIMatrix();
  277. {
  278. const LLRect& r = mHintMin->getRect();
  279. F32 left = (F32)(r.mLeft + BTN_BORDER);
  280. F32 bot = (F32)(r.mBottom + BTN_BORDER);
  281. gGL.translateUI(left, bot, 0.f);
  282. mHintMin->draw();
  283. }
  284. gGL.popUIMatrix();
  285. gGL.pushUIMatrix();
  286. {
  287. const LLRect& r = mHintMax->getRect();
  288. F32 left = (F32)(r.mLeft + BTN_BORDER);
  289. F32 bot = (F32)(r.mBottom + BTN_BORDER);
  290. gGL.translateUI(left, bot, 0.f);
  291. mHintMax->draw();
  292. }
  293. gGL.popUIMatrix();
  294. }
  295. // Draw labels on top of the buttons
  296. if (mMinParamText)
  297. {
  298. mMinParamText->setVisible(true);
  299. drawChild(mMinParamText, BTN_BORDER, BTN_BORDER);
  300. }
  301. if (mMaxParamText)
  302. {
  303. mMaxParamText->setVisible(true);
  304. drawChild(mMaxParamText, BTN_BORDER, BTN_BORDER);
  305. }
  306. }
  307. // static
  308. void LLScrollingPanelParam::onSliderMoved(LLUICtrl* ctrl, void* userdata)
  309. {
  310. LLSliderCtrl* slider = (LLSliderCtrl*)ctrl;
  311. LLScrollingPanelParam* self = (LLScrollingPanelParam*)userdata;
  312. if (self && self->mWearable && slider && isAgentAvatarValid())
  313. {
  314. LLViewerVisualParam* param = self->mParam;
  315. F32 current_weight = self->mWearable->getVisualParamWeight(param->getID());
  316. F32 new_weight = self->percentToWeight((F32)slider->getValue().asReal());
  317. if (current_weight != new_weight)
  318. {
  319. self->mWearable->setVisualParamWeight(param->getID(),
  320. new_weight, false);
  321. self->mWearable->writeToAvatar(gAgentAvatarp);
  322. gAgentAvatarp->updateVisualParams();
  323. if (gFloaterCustomizep)
  324. {
  325. gFloaterCustomizep->updateAvatarHeightDisplay();
  326. }
  327. if ((U32)param->getID() == LLAvatarAppearanceDefines::AVATAR_HOVER)
  328. {
  329. if (LLVOAvatarSelf::canUseServerBaking() &&
  330. !LLVOAvatarSelf::useAvatarHoverHeight())
  331. {
  332. #if 1
  333. static LLCachedControl<F32> factor(gSavedSettings,
  334. "HoverToZOffsetFactor");
  335. if (factor > 1.f)
  336. {
  337. // Hover is wrongly accounted twice in LL's viewer...
  338. new_weight *= factor;
  339. }
  340. #endif
  341. gSavedSettings.setF32("AvatarOffsetZ", new_weight);
  342. }
  343. }
  344. }
  345. }
  346. }
  347. // static
  348. void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata)
  349. {
  350. }
  351. // static
  352. void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata)
  353. {
  354. LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
  355. if (self)
  356. {
  357. LLVisualParamHint::requestHintUpdates(self->mHintMin, self->mHintMax);
  358. }
  359. }
  360. // static
  361. void LLScrollingPanelParam::onHintMinMouseDown(void* userdata)
  362. {
  363. LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
  364. if (self)
  365. {
  366. self->onHintMouseDown(self->mHintMin);
  367. }
  368. }
  369. // static
  370. void LLScrollingPanelParam::onHintMaxMouseDown(void* userdata)
  371. {
  372. LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
  373. if (self)
  374. {
  375. self->onHintMouseDown(self->mHintMax);
  376. }
  377. }
  378. void LLScrollingPanelParam::onHintMouseDown(LLVisualParamHint* hint)
  379. {
  380. if (hint && mWearable && isAgentAvatarValid())
  381. {
  382. // morph towards this result
  383. F32 current_weight = mWearable->getVisualParamWeight(hint->getVisualParam()->getID());
  384. // if we have maxed out on this morph, we shouldn't be able to click it
  385. if (hint->getVisualParamWeight() != current_weight)
  386. {
  387. mMouseDownTimer.reset();
  388. mLastHeldTime = 0.f;
  389. }
  390. }
  391. }
  392. // static
  393. void LLScrollingPanelParam::onHintMinHeldDown(void* userdata)
  394. {
  395. LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
  396. if (self)
  397. {
  398. self->onHintHeldDown(self->mHintMin);
  399. }
  400. }
  401. // static
  402. void LLScrollingPanelParam::onHintMaxHeldDown(void* userdata)
  403. {
  404. LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
  405. if (self)
  406. {
  407. self->onHintHeldDown(self->mHintMax);
  408. }
  409. }
  410. void LLScrollingPanelParam::onHintHeldDown(LLVisualParamHint* hint)
  411. {
  412. if (!hint || !mWearable || !isAgentAvatarValid()) return;
  413. F32 current_weight = mWearable->getVisualParamWeight(hint->getVisualParam()->getID());
  414. if (current_weight != hint->getVisualParamWeight())
  415. {
  416. constexpr F32 FULL_BLEND_TIME = 2.f;
  417. F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime;
  418. mLastHeldTime += elapsed_time;
  419. F32 new_weight;
  420. if (current_weight > hint->getVisualParamWeight())
  421. {
  422. new_weight = current_weight - elapsed_time / FULL_BLEND_TIME;
  423. }
  424. else
  425. {
  426. new_weight = current_weight + elapsed_time / FULL_BLEND_TIME;
  427. }
  428. // Make sure we're not taking the slider out of bounds
  429. // (this is where some simple UI limits are stored)
  430. F32 new_percent = weightToPercent(new_weight);
  431. if (mSlider)
  432. {
  433. if (mSlider->getMinValue() < new_percent &&
  434. new_percent < mSlider->getMaxValue())
  435. {
  436. mWearable->setVisualParamWeight(hint->getVisualParam()->getID(),
  437. new_weight, false);
  438. mWearable->writeToAvatar(gAgentAvatarp);
  439. gAgentAvatarp->updateVisualParams();
  440. mSlider->setValue(weightToPercent(new_weight));
  441. }
  442. }
  443. }
  444. }
  445. // static
  446. void LLScrollingPanelParam::onHintMinMouseUp(void* userdata)
  447. {
  448. LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
  449. if (self && self->mWearable && isAgentAvatarValid())
  450. {
  451. F32 elapsed_time = self->mMouseDownTimer.getElapsedTimeF32();
  452. LLVisualParamHint* hint = self->mHintMin;
  453. if (hint && elapsed_time < PARAM_STEP_TIME_THRESHOLD)
  454. {
  455. // step in direction
  456. F32 current_weight = self->mWearable->getVisualParamWeight(hint->getVisualParam()->getID());
  457. F32 range = self->mHintMax->getVisualParamWeight() -
  458. self->mHintMin->getVisualParamWeight();
  459. // step a fraction in the negative direction
  460. F32 new_weight = current_weight - range / 10.f;
  461. F32 new_percent = self->weightToPercent(new_weight);
  462. if (self->mSlider)
  463. {
  464. if (self->mSlider->getMinValue() < new_percent &&
  465. new_percent < self->mSlider->getMaxValue())
  466. {
  467. self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(),
  468. new_weight, true);
  469. self->mWearable->writeToAvatar(gAgentAvatarp);
  470. self->mSlider->setValue(self->weightToPercent(new_weight));
  471. }
  472. }
  473. }
  474. LLVisualParamHint::requestHintUpdates(self->mHintMin, self->mHintMax);
  475. }
  476. }
  477. void LLScrollingPanelParam::onHintMaxMouseUp(void* userdata)
  478. {
  479. LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata;
  480. if (self && self->mWearable && isAgentAvatarValid())
  481. {
  482. F32 elapsed_time = self->mMouseDownTimer.getElapsedTimeF32();
  483. LLVisualParamHint* hint = self->mHintMax;
  484. if (hint && elapsed_time < PARAM_STEP_TIME_THRESHOLD)
  485. {
  486. // step in direction
  487. F32 current_weight = self->mWearable->getVisualParamWeight(hint->getVisualParam()->getID());
  488. F32 range = self->mHintMax->getVisualParamWeight() -
  489. self->mHintMin->getVisualParamWeight();
  490. // step a fraction in the negative direction
  491. F32 new_weight = current_weight + range / 10.f;
  492. F32 new_percent = self->weightToPercent(new_weight);
  493. if (self->mSlider)
  494. {
  495. if (self->mSlider->getMinValue() < new_percent &&
  496. new_percent < self->mSlider->getMaxValue())
  497. {
  498. self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(),
  499. new_weight, true);
  500. self->mWearable->writeToAvatar(gAgentAvatarp);
  501. self->mSlider->setValue(self->weightToPercent(new_weight));
  502. }
  503. }
  504. }
  505. LLVisualParamHint::requestHintUpdates(self->mHintMin, self->mHintMax);
  506. }
  507. }
  508. F32 LLScrollingPanelParam::weightToPercent(F32 weight)
  509. {
  510. LLViewerVisualParam* param = mParam;
  511. return (weight - param->getMinWeight()) /
  512. (param->getMaxWeight() - param->getMinWeight()) * 100.f;
  513. }
  514. F32 LLScrollingPanelParam::percentToWeight(F32 percent)
  515. {
  516. LLViewerVisualParam* param = mParam;
  517. return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) +
  518. param->getMinWeight();
  519. }