llsliderctrl.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. /**
  2. * @file llsliderctrl.cpp
  3. * @brief LLSliderCtrl base class
  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 "linden_common.h"
  33. #include "llsliderctrl.h"
  34. #include "llcontrol.h"
  35. #include "llgl.h"
  36. #include "llimagegl.h"
  37. #include "llkeyboard.h"
  38. #include "lllineeditor.h"
  39. #include "lllocale.h"
  40. #include "lltextbox.h"
  41. #include "llwindow.h"
  42. constexpr U32 MAX_SLIDER_STR_LEN = 10;
  43. static const std::string LL_SLIDER_CTRL_TAG = "slider";
  44. static LLRegisterWidget<LLSliderCtrl> r23(LL_SLIDER_CTRL_TAG);
  45. ///////////////////////////////////////////////////////////////////////////////
  46. // LLSlider class (actuak slider sub-element of LLSliderCtrl).
  47. ///////////////////////////////////////////////////////////////////////////////
  48. LLSlider::LLSlider(const std::string& name, const LLRect& rect,
  49. void (*on_commit_callback)(LLUICtrl*, void*),
  50. void* callback_userdata,
  51. F32 initial_value, F32 min_value, F32 max_value,
  52. F32 increment, const char* control_name)
  53. : LLUICtrl(name, rect, true, on_commit_callback, callback_userdata,
  54. FOLLOWS_LEFT | FOLLOWS_TOP),
  55. mValue(initial_value),
  56. mInitialValue(initial_value),
  57. mMinValue(min_value),
  58. mMaxValue(max_value),
  59. mIncrement(increment),
  60. mMouseOffset(0),
  61. mMouseDownCallback(NULL),
  62. mMouseUpCallback(NULL),
  63. mMouseHoverCallback(NULL)
  64. {
  65. mThumbImage = LLUI::getUIImage("icn_slide-thumb_dark.tga");
  66. mTrackImage = LLUI::getUIImage("icn_slide-groove_dark.tga");
  67. mTrackHighlightImage = LLUI::getUIImage("icn_slide-highlight.tga");
  68. // Properly handle setting the starting thumb rect: do it this way to
  69. // handle both the operating-on-settings and standalone ways of using this
  70. setControlName(control_name, NULL);
  71. setValue(getValueF32());
  72. updateThumbRect();
  73. mDragStartThumbRect = mThumbRect;
  74. }
  75. //virtual
  76. void LLSlider::setValue(F32 value, bool from_event)
  77. {
  78. value = llclamp(value, mMinValue, mMaxValue);
  79. // Round to nearest increment (bias towards rounding down)
  80. value -= mMinValue;
  81. value += mIncrement / 2.0001f;
  82. value -= fmod(value, mIncrement);
  83. value += mMinValue;
  84. if (!from_event && mValue != value)
  85. {
  86. setControlValue(value);
  87. }
  88. mValue = value;
  89. updateThumbRect();
  90. }
  91. void LLSlider::updateThumbRect()
  92. {
  93. F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
  94. S32 thumb_width = mThumbImage->getWidth();
  95. S32 thumb_height = mThumbImage->getHeight();
  96. S32 left_edge = thumb_width / 2;
  97. S32 right_edge = getRect().getWidth() - thumb_width / 2;
  98. S32 x = left_edge + S32(t * (right_edge - left_edge));
  99. mThumbRect.mLeft = x - (thumb_width / 2);
  100. mThumbRect.mRight = mThumbRect.mLeft + thumb_width;
  101. mThumbRect.mBottom = getLocalRect().getCenterY() - thumb_height / 2;
  102. mThumbRect.mTop = mThumbRect.mBottom + thumb_height;
  103. }
  104. void LLSlider::setValueAndCommit(F32 value)
  105. {
  106. F32 old_value = mValue;
  107. setValue(value);
  108. if (value != old_value)
  109. {
  110. onCommit();
  111. }
  112. }
  113. //virtual
  114. bool LLSlider::handleHover(S32 x, S32 y, MASK mask)
  115. {
  116. if (hasMouseCapture())
  117. {
  118. if (mMouseHoverCallback)
  119. {
  120. mMouseHoverCallback(this, mCallbackUserData);
  121. }
  122. S32 thumb_half_width = mThumbImage->getWidth() / 2;
  123. S32 left_edge = thumb_half_width;
  124. S32 right_edge = getRect().getWidth() - (thumb_half_width);
  125. x += mMouseOffset;
  126. x = llclamp(x, left_edge, right_edge);
  127. F32 t = F32(x - left_edge) / (right_edge - left_edge);
  128. setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue);
  129. gWindowp->setCursor(UI_CURSOR_ARROW);
  130. LL_DEBUGS("UserInput") << "hover handled by " << getName()
  131. << " (active)" << LL_ENDL;
  132. }
  133. else
  134. {
  135. gWindowp->setCursor(UI_CURSOR_ARROW);
  136. LL_DEBUGS("UserInput") << "hover handled by " << getName()
  137. << " (inactive)" << LL_ENDL;
  138. }
  139. return true;
  140. }
  141. //virtual
  142. bool LLSlider::handleMouseUp(S32 x, S32 y, MASK mask)
  143. {
  144. if (hasMouseCapture())
  145. {
  146. gFocusMgr.setMouseCapture(NULL);
  147. if (mMouseUpCallback)
  148. {
  149. mMouseUpCallback(this, mCallbackUserData);
  150. }
  151. make_ui_sound("UISndClickRelease");
  152. }
  153. return true;
  154. }
  155. //virtual
  156. bool LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
  157. {
  158. // Only do sticky-focus on non-chrome widgets
  159. if (!getIsChrome())
  160. {
  161. setFocus(true);
  162. }
  163. if (mMouseDownCallback)
  164. {
  165. mMouseDownCallback(this, mCallbackUserData);
  166. }
  167. if (MASK_CONTROL & mask) // if CTRL is modifying
  168. {
  169. setValueAndCommit(mInitialValue);
  170. }
  171. else
  172. {
  173. // Find the offset of the actual mouse location from the center of the
  174. // thumb.
  175. if (mThumbRect.pointInRect(x, y))
  176. {
  177. mMouseOffset = mThumbRect.mLeft + mThumbImage->getWidth() / 2 - x;
  178. }
  179. else
  180. {
  181. mMouseOffset = 0;
  182. }
  183. // Start dragging the thumb
  184. // No handler needed for focus lost since this class has no state that
  185. // depends on it.
  186. gFocusMgr.setMouseCapture(this);
  187. mDragStartThumbRect = mThumbRect;
  188. }
  189. make_ui_sound("UISndClick");
  190. return true;
  191. }
  192. //virtual
  193. bool LLSlider::handleKeyHere(KEY key, MASK mask)
  194. {
  195. switch (key)
  196. {
  197. case KEY_UP:
  198. case KEY_DOWN:
  199. // Eat up and down keys to be consistent
  200. return true;
  201. case KEY_LEFT:
  202. setValueAndCommit(getValueF32() - getIncrement());
  203. return true;
  204. case KEY_RIGHT:
  205. setValueAndCommit(getValueF32() + getIncrement());
  206. return true;
  207. default:
  208. break;
  209. }
  210. return false;
  211. }
  212. //virtual
  213. void LLSlider::draw()
  214. {
  215. // Since thumb image might still be decoding, need thumb to accomodate
  216. // image size
  217. updateThumbRect();
  218. // Draw background and thumb.
  219. // Drawing solids requires texturing be disabled
  220. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  221. F32 opacity = getEnabled() ? 1.f : 0.3f;
  222. LLColor4 center_color = LLUI::sSliderThumbCenterColor % opacity;
  223. // Track
  224. S32 half_width = mThumbImage->getWidth() / 2;
  225. S32 half_height = mTrackImage->getHeight() / 2;
  226. LLRect track_rect(half_width, getLocalRect().getCenterY() + half_height,
  227. getRect().getWidth() - half_width,
  228. getLocalRect().getCenterY() - half_height);
  229. LLRect highlight_rect(track_rect.mLeft, track_rect.mTop,
  230. mThumbRect.getCenterX(), track_rect.mBottom);
  231. mTrackImage->draw(track_rect);
  232. mTrackHighlightImage->draw(highlight_rect);
  233. // Thumb
  234. if (hasMouseCapture())
  235. {
  236. // Show ghost where thumb was before dragging began.
  237. mThumbImage->draw(mDragStartThumbRect,
  238. LLUI::sSliderThumbCenterColor % 0.3f);
  239. }
  240. if (hasFocus())
  241. {
  242. // Draw focus highlighting.
  243. mThumbImage->drawBorder(mThumbRect, gFocusMgr.getFocusColor(),
  244. gFocusMgr.getFocusFlashWidth());
  245. }
  246. // Fill in the thumb.
  247. mThumbImage->draw(mThumbRect, hasMouseCapture() ?
  248. LLUI::sSliderThumbOutlineColor : center_color);
  249. LLUICtrl::draw();
  250. }
  251. LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect,
  252. const std::string& label, const LLFontGL* font,
  253. S32 label_width, S32 text_left, bool show_text,
  254. bool can_edit_text,
  255. void (*commit_callback)(LLUICtrl*, void*),
  256. void* callback_user_data, F32 initial_value,
  257. F32 min_value, F32 max_value, F32 increment,
  258. const char* control_name)
  259. : LLUICtrl(name, rect, true, commit_callback, callback_user_data),
  260. mFont(font),
  261. mShowText(show_text),
  262. mCanEditText(can_edit_text),
  263. mPrecision(3),
  264. mLabelBox(NULL),
  265. mLabelWidth(label_width),
  266. mValue(initial_value),
  267. mEditor(NULL),
  268. mTextBox(NULL),
  269. mTextEnabledColor(LLUI::sLabelTextColor),
  270. mTextDisabledColor(LLUI::sLabelDisabledColor),
  271. mSliderMouseUpCallback(NULL),
  272. mSliderMouseDownCallback(NULL)
  273. {
  274. S32 top = getRect().getHeight();
  275. S32 bottom = 0;
  276. S32 left = 0;
  277. // Label
  278. if (!label.empty())
  279. {
  280. if (label_width == 0)
  281. {
  282. label_width = font->getWidth(label);
  283. }
  284. LLRect label_rect(left, top, label_width, bottom);
  285. mLabelBox = new LLTextBox("SliderCtrl Label", label_rect, label, font);
  286. addChild(mLabelBox);
  287. }
  288. S32 slider_right = getRect().getWidth();
  289. if (show_text)
  290. {
  291. slider_right = text_left - SLIDERCTRL_SPACING;
  292. }
  293. S32 slider_left = label_width ? label_width + SLIDERCTRL_SPACING : 0;
  294. LLRect slider_rect(slider_left, top, slider_right, bottom);
  295. mSlider = new LLSlider(LL_SLIDER_CTRL_TAG, slider_rect,
  296. LLSliderCtrl::onSliderCommit, this, initial_value,
  297. min_value, max_value, increment, control_name);
  298. addChild(mSlider);
  299. if (show_text)
  300. {
  301. LLRect text_rect(text_left, top, getRect().getWidth(), bottom);
  302. if (can_edit_text)
  303. {
  304. mEditor = new LLLineEditor("SliderCtrl Editor", text_rect,
  305. LLStringUtil::null, font,
  306. MAX_SLIDER_STR_LEN,
  307. &LLSliderCtrl::onEditorCommit,
  308. NULL, NULL, this,
  309. &LLLineEditor::prevalidateFloat);
  310. mEditor->setFollowsLeft();
  311. mEditor->setFollowsBottom();
  312. mEditor->setFocusReceivedCallback(&LLSliderCtrl::onEditorGainFocus,
  313. this);
  314. mEditor->setIgnoreTab(true);
  315. #if 0 // Do not do this, as selecting the entire text is single clicking
  316. // in some cases and double clicking in others
  317. mEditor->setSelectAllonFocusReceived(true);
  318. #endif
  319. addChild(mEditor);
  320. }
  321. else
  322. {
  323. mTextBox = new LLTextBox("SliderCtrl Text", text_rect,
  324. LLStringUtil::null, font);
  325. mTextBox->setFollowsLeft();
  326. mTextBox->setFollowsBottom();
  327. addChild(mTextBox);
  328. }
  329. }
  330. updateText();
  331. }
  332. //virtual
  333. LLSliderCtrl::~LLSliderCtrl()
  334. {
  335. // Children all cleaned up by default view destructor.
  336. }
  337. //static
  338. void LLSliderCtrl::onEditorGainFocus(LLFocusableElement* caller,
  339. void* userdata)
  340. {
  341. LLSliderCtrl* self = (LLSliderCtrl*)userdata;
  342. llassert(caller == self->mEditor);
  343. self->onFocusReceived();
  344. }
  345. //virtual
  346. void LLSliderCtrl::setValue(F32 v, bool from_event)
  347. {
  348. mSlider->setValue(v, from_event);
  349. mValue = mSlider->getValueF32();
  350. updateText();
  351. }
  352. void LLSliderCtrl::setLabel(const std::string& label)
  353. {
  354. if (mLabelBox)
  355. {
  356. mLabelBox->setText(label);
  357. }
  358. }
  359. //virtual
  360. bool LLSliderCtrl::setLabelArg(const std::string& key,
  361. const std::string& text)
  362. {
  363. bool res = false;
  364. if (mLabelBox)
  365. {
  366. res = mLabelBox->setTextArg(key, text);
  367. if (res && mLabelWidth == 0)
  368. {
  369. S32 label_width = mFont->getWidth(mLabelBox->getText());
  370. LLRect rect = mLabelBox->getRect();
  371. S32 prev_right = rect.mRight;
  372. rect.mRight = rect.mLeft + label_width;
  373. mLabelBox->setRect(rect);
  374. S32 delta = rect.mRight - prev_right;
  375. rect = mSlider->getRect();
  376. S32 left = rect.mLeft + delta;
  377. left = llclamp(left, 0, rect.mRight - SLIDERCTRL_SPACING);
  378. rect.mLeft = left;
  379. mSlider->setRect(rect);
  380. }
  381. }
  382. return res;
  383. }
  384. //virtual
  385. void LLSliderCtrl::clear()
  386. {
  387. setValue(0.f);
  388. if (mEditor)
  389. {
  390. mEditor->setText(LLStringUtil::null);
  391. }
  392. if (mTextBox)
  393. {
  394. mTextBox->setText(LLStringUtil::null);
  395. }
  396. }
  397. void LLSliderCtrl::setOffLimit(const std::string& off_text, F32 off_value)
  398. {
  399. mDisplayOff = off_text.size() > 0;
  400. mOffText = off_text;
  401. mOffValue = off_value;
  402. if (mTextBox && !mEditor)
  403. {
  404. updateText();
  405. }
  406. }
  407. void LLSliderCtrl::updateText()
  408. {
  409. if (mEditor || mTextBox)
  410. {
  411. LLLocale locale(LLLocale::USER_LOCALE);
  412. // Do not display very small negative values as -0.000
  413. F32 displayed_value = floorf(getValueF32() *
  414. powf(10.f, mPrecision) + 0.5f) /
  415. powf(10.f, mPrecision);
  416. std::string format = llformat("%%.%df", mPrecision);
  417. std::string text = llformat(format.c_str(), displayed_value);
  418. if (mEditor)
  419. {
  420. mEditor->setText(text);
  421. }
  422. else if (mDisplayOff && displayed_value == mOffValue)
  423. {
  424. mTextBox->setText(mOffText);
  425. }
  426. else
  427. {
  428. mTextBox->setText(text);
  429. }
  430. }
  431. }
  432. void LLSliderCtrl::updateSliderRect()
  433. {
  434. S32 left = 0;
  435. S32 right = getRect().getWidth();
  436. S32 top = getRect().getHeight();
  437. S32 bottom = 0;
  438. if (mEditor)
  439. {
  440. LLRect editor_rect = mEditor->getRect();
  441. S32 editor_width = editor_rect.getWidth();
  442. editor_rect.mRight = right;
  443. editor_rect.mLeft = right - editor_width;
  444. mEditor->setRect(editor_rect);
  445. right -= editor_width + SLIDERCTRL_SPACING;
  446. }
  447. if (mTextBox)
  448. {
  449. right -= mTextBox->getRect().getWidth() + SLIDERCTRL_SPACING;
  450. }
  451. if (mLabelBox)
  452. {
  453. left += mLabelBox->getRect().getWidth() + SLIDERCTRL_SPACING;
  454. }
  455. mSlider->setRect(LLRect(left, top, right, bottom));
  456. }
  457. //static
  458. void LLSliderCtrl::onEditorCommit(LLUICtrl* caller, void *userdata)
  459. {
  460. LLSliderCtrl* self = (LLSliderCtrl*) userdata;
  461. llassert(caller == self->mEditor);
  462. bool success = false;
  463. F32 val = self->mValue;
  464. F32 saved_val = self->mValue;
  465. std::string text = self->mEditor->getText();
  466. if (LLLineEditor::postvalidateFloat(text))
  467. {
  468. LLLocale locale(LLLocale::USER_LOCALE);
  469. val = (F32) atof(text.c_str());
  470. if (self->mSlider->getMinValue() <= val &&
  471. val <= self->mSlider->getMaxValue())
  472. {
  473. if (self->mValidateCallback)
  474. {
  475. // Set the value temporarily so that the callback can retrieve
  476. // it:
  477. self->setValue(val);
  478. if (self->mValidateCallback(self, self->mCallbackUserData))
  479. {
  480. success = true;
  481. }
  482. }
  483. else
  484. {
  485. self->setValue(val);
  486. success = true;
  487. }
  488. }
  489. }
  490. if (success)
  491. {
  492. self->onCommit();
  493. }
  494. else
  495. {
  496. if (self->getValueF32() != saved_val)
  497. {
  498. self->setValue(saved_val);
  499. }
  500. self->reportInvalidData();
  501. }
  502. self->updateText();
  503. }
  504. //static
  505. void LLSliderCtrl::onSliderCommit(LLUICtrl* caller, void *userdata)
  506. {
  507. LLSliderCtrl* self = (LLSliderCtrl*)userdata;
  508. llassert(caller == self->mSlider);
  509. bool success = false;
  510. F32 saved_val = self->mValue;
  511. F32 new_val = self->mSlider->getValueF32();
  512. if (self->mValidateCallback)
  513. {
  514. // set the value temporarily so that the callback can retrieve it:
  515. self->mValue = new_val;
  516. if (self->mValidateCallback(self, self->mCallbackUserData))
  517. {
  518. success = true;
  519. }
  520. }
  521. else
  522. {
  523. self->mValue = new_val;
  524. success = true;
  525. }
  526. if (success)
  527. {
  528. self->onCommit();
  529. }
  530. else
  531. {
  532. if (self->mValue != saved_val)
  533. {
  534. self->setValue(saved_val);
  535. }
  536. self->reportInvalidData();
  537. }
  538. self->updateText();
  539. }
  540. //virtual
  541. void LLSliderCtrl::setEnabled(bool b)
  542. {
  543. LLView::setEnabled(b);
  544. if (mLabelBox)
  545. {
  546. mLabelBox->setColor(b ? mTextEnabledColor : mTextDisabledColor);
  547. }
  548. mSlider->setEnabled(b);
  549. if (mEditor)
  550. {
  551. mEditor->setEnabled(b);
  552. }
  553. if (mTextBox)
  554. {
  555. mTextBox->setColor(b ? mTextEnabledColor : mTextDisabledColor);
  556. }
  557. }
  558. //virtual
  559. void LLSliderCtrl::setTentative(bool b)
  560. {
  561. if (mEditor)
  562. {
  563. mEditor->setTentative(b);
  564. }
  565. LLUICtrl::setTentative(b);
  566. }
  567. //virtual
  568. void LLSliderCtrl::onCommit()
  569. {
  570. setTentative(false);
  571. if (mEditor)
  572. {
  573. mEditor->setTentative(false);
  574. }
  575. LLUICtrl::onCommit();
  576. }
  577. //virtual
  578. void LLSliderCtrl::setRect(const LLRect& rect)
  579. {
  580. LLUICtrl::setRect(rect);
  581. updateSliderRect();
  582. }
  583. //virtual
  584. void LLSliderCtrl::reshape(S32 width, S32 height, bool called_from_parent)
  585. {
  586. LLUICtrl::reshape(width, height, called_from_parent);
  587. updateSliderRect();
  588. }
  589. //virtual
  590. void LLSliderCtrl::setPrecision(S32 precision)
  591. {
  592. if (precision < 0 || precision > 10)
  593. {
  594. llerrs << "LLSliderCtrl::setPrecision - precision out of range"
  595. << llendl;
  596. return;
  597. }
  598. mPrecision = precision;
  599. updateText();
  600. }
  601. void LLSliderCtrl::setSliderMouseDownCallback(void (*cb)(LLUICtrl*, void*))
  602. {
  603. mSliderMouseDownCallback = cb;
  604. mSlider->setMouseDownCallback(LLSliderCtrl::onSliderMouseDown);
  605. }
  606. //static
  607. void LLSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
  608. {
  609. LLSliderCtrl* self = (LLSliderCtrl*) userdata;
  610. if (self->mSliderMouseDownCallback)
  611. {
  612. self->mSliderMouseDownCallback(self, self->mCallbackUserData);
  613. }
  614. }
  615. void LLSliderCtrl::setSliderMouseUpCallback(void (*cb)(LLUICtrl*, void*))
  616. {
  617. mSliderMouseUpCallback = cb;
  618. mSlider->setMouseUpCallback(LLSliderCtrl::onSliderMouseUp);
  619. }
  620. //static
  621. void LLSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata)
  622. {
  623. LLSliderCtrl* self = (LLSliderCtrl*) userdata;
  624. if (self->mSliderMouseUpCallback)
  625. {
  626. self->mSliderMouseUpCallback(self, self->mCallbackUserData);
  627. }
  628. }
  629. //virtual
  630. void LLSliderCtrl::onTabInto()
  631. {
  632. if (mEditor)
  633. {
  634. mEditor->onTabInto();
  635. }
  636. }
  637. void LLSliderCtrl::reportInvalidData()
  638. {
  639. make_ui_sound("UISndBadKeystroke");
  640. }
  641. //virtual
  642. void LLSliderCtrl::setControlName(const char* control_name, LLView* context)
  643. {
  644. LLView::setControlName(control_name, context);
  645. mSlider->setControlName(control_name, context);
  646. }
  647. //virtual
  648. const std::string& LLSliderCtrl::getTag() const
  649. {
  650. return LL_SLIDER_CTRL_TAG;
  651. }
  652. //virtual
  653. LLXMLNodePtr LLSliderCtrl::getXML(bool save_children) const
  654. {
  655. LLXMLNodePtr node = LLUICtrl::getXML();
  656. node->setName(LL_SLIDER_CTRL_TAG);
  657. node->createChild("show_text", true)->setBoolValue(mShowText);
  658. node->createChild("can_edit_text", true)->setBoolValue(mCanEditText);
  659. node->createChild("decimal_digits", true)->setIntValue(mPrecision);
  660. if (mLabelBox)
  661. {
  662. node->createChild("label", true)->setStringValue(mLabelBox->getText());
  663. }
  664. // TomY TODO: Do we really want to export the transient state of the slider?
  665. node->createChild("value", true)->setFloatValue(mValue);
  666. if (mSlider)
  667. {
  668. node->createChild("initial_val", true)->setFloatValue(mSlider->getInitialValue());
  669. node->createChild("min_val", true)->setFloatValue(mSlider->getMinValue());
  670. node->createChild("max_val", true)->setFloatValue(mSlider->getMaxValue());
  671. node->createChild("increment", true)->setFloatValue(mSlider->getIncrement());
  672. }
  673. addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor");
  674. addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor");
  675. return node;
  676. }
  677. //static
  678. LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView* parent,
  679. LLUICtrlFactory*)
  680. {
  681. std::string name = LL_SLIDER_CTRL_TAG;
  682. node->getAttributeString("name", name);
  683. std::string label;
  684. node->getAttributeString("label", label);
  685. LLRect rect;
  686. createRect(node, rect, parent, LLRect());
  687. LLFontGL* font = LLView::selectFont(node);
  688. // *HACK: Font might not be specified.
  689. if (!font)
  690. {
  691. font = LLFontGL::getFontSansSerifSmall();
  692. }
  693. S32 label_width = 0;
  694. node->getAttributeS32("label_width", label_width);
  695. bool show_text = true;
  696. node->getAttributeBool("show_text", show_text);
  697. bool can_edit_text = false;
  698. node->getAttributeBool("can_edit_text", can_edit_text);
  699. F32 initial_value = 0.f;
  700. node->getAttributeF32("initial_val", initial_value);
  701. F32 min_value = 0.f;
  702. node->getAttributeF32("min_val", min_value);
  703. F32 max_value = 1.f;
  704. node->getAttributeF32("max_val", max_value);
  705. F32 increment = 0.1f;
  706. node->getAttributeF32("increment", increment);
  707. U32 precision = 3;
  708. node->getAttributeU32("decimal_digits", precision);
  709. S32 text_left = 0;
  710. if (show_text)
  711. {
  712. // Calculate the size of the text box (log max_value is number of
  713. // digits - 1 so plus 1)
  714. if (max_value)
  715. {
  716. text_left = font->getWidth("0") *
  717. ((S32)log10f(max_value) + precision + 1);
  718. }
  719. if (increment < 1.f)
  720. {
  721. // (mostly) take account of decimal point in value
  722. text_left += font->getWidth(".");
  723. }
  724. if (min_value < 0.f || max_value < 0.f)
  725. {
  726. // (mostly) take account of minus sign
  727. text_left += font->getWidth("-");
  728. }
  729. // Padding to make things look nicer
  730. text_left += 8;
  731. }
  732. if (label.empty())
  733. {
  734. label.assign(node->getTextContents());
  735. }
  736. LLUICtrlCallback callback = NULL;
  737. LLSliderCtrl* slider =
  738. new LLSliderCtrl(name, rect, label, font, label_width,
  739. rect.getWidth() - text_left, show_text, can_edit_text,
  740. callback, NULL, initial_value, min_value,
  741. max_value, increment);
  742. slider->setPrecision(precision);
  743. slider->initFromXML(node, parent);
  744. slider->updateText();
  745. return slider;
  746. }