PageRenderTime 38ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llui/llmultisliderctrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 489 lines | 375 code | 72 blank | 42 comment | 49 complexity | cd64cac0c3b14f149c1eb4487e18d96c MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llmultisliderctrl.cpp
  3. * @brief LLMultiSliderCtrl base class
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llmultisliderctrl.h"
  28. #include "llmath.h"
  29. #include "llfontgl.h"
  30. #include "llgl.h"
  31. #include "llkeyboard.h"
  32. #include "lllineeditor.h"
  33. #include "llmultislider.h"
  34. #include "llstring.h"
  35. #include "lltextbox.h"
  36. #include "llui.h"
  37. #include "lluiconstants.h"
  38. #include "llcontrol.h"
  39. #include "llfocusmgr.h"
  40. #include "llresmgr.h"
  41. #include "lluictrlfactory.h"
  42. static LLDefaultChildRegistry::Register<LLMultiSliderCtrl> r("multi_slider");
  43. const U32 MAX_STRING_LENGTH = 10;
  44. LLMultiSliderCtrl::Params::Params()
  45. : text_width("text_width"),
  46. label_width("label_width"),
  47. show_text("show_text", true),
  48. can_edit_text("can_edit_text", false),
  49. max_sliders("max_sliders", 1),
  50. allow_overlap("allow_overlap", false),
  51. draw_track("draw_track", true),
  52. use_triangle("use_triangle", false),
  53. decimal_digits("decimal_digits", 3),
  54. text_color("text_color"),
  55. text_disabled_color("text_disabled_color"),
  56. mouse_down_callback("mouse_down_callback"),
  57. mouse_up_callback("mouse_up_callback"),
  58. sliders("slider")
  59. {
  60. mouse_opaque = true;
  61. }
  62. LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
  63. : LLF32UICtrl(p),
  64. mLabelBox( NULL ),
  65. mEditor( NULL ),
  66. mTextBox( NULL ),
  67. mTextEnabledColor(p.text_color()),
  68. mTextDisabledColor(p.text_disabled_color())
  69. {
  70. static LLUICachedControl<S32> multi_sliderctrl_spacing ("UIMultiSliderctrlSpacing", 0);
  71. S32 top = getRect().getHeight();
  72. S32 bottom = 0;
  73. S32 left = 0;
  74. S32 label_width = p.label_width;
  75. S32 text_width = p.text_width;
  76. // Label
  77. if( !p.label().empty() )
  78. {
  79. if (p.label_width == 0)
  80. {
  81. label_width = p.font()->getWidth(p.label);
  82. }
  83. LLRect label_rect( left, top, label_width, bottom );
  84. LLTextBox::Params params;
  85. params.name("MultiSliderCtrl Label");
  86. params.rect(label_rect);
  87. params.initial_value(p.label());
  88. params.font(p.font);
  89. mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
  90. addChild(mLabelBox);
  91. }
  92. S32 slider_right = getRect().getWidth();
  93. if (p.show_text)
  94. {
  95. if (!p.text_width.isProvided())
  96. {
  97. text_width = 0;
  98. // calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
  99. if ( p.max_value() )
  100. text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10 ( p.max_value ) ) + p.decimal_digits + 1 );
  101. if ( p.increment < 1.0f )
  102. text_width += p.font()->getWidth(std::string(".")); // (mostly) take account of decimal point in value
  103. if ( p.min_value < 0.0f || p.max_value < 0.0f )
  104. text_width += p.font()->getWidth(std::string("-")); // (mostly) take account of minus sign
  105. // padding to make things look nicer
  106. text_width += 8;
  107. }
  108. S32 text_left = getRect().getWidth() - text_width;
  109. slider_right = text_left - multi_sliderctrl_spacing;
  110. LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
  111. if( p.can_edit_text )
  112. {
  113. LLLineEditor::Params params;
  114. params.name("MultiSliderCtrl Editor");
  115. params.rect(text_rect);
  116. params.font(p.font);
  117. params.max_length.bytes(MAX_STRING_LENGTH);
  118. params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
  119. params.prevalidate_callback(&LLTextValidate::validateFloat);
  120. params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
  121. mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
  122. mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) );
  123. // don't do this, as selecting the entire text is single clicking in some cases
  124. // and double clicking in others
  125. //mEditor->setSelectAllonFocusReceived(TRUE);
  126. addChild(mEditor);
  127. }
  128. else
  129. {
  130. LLTextBox::Params params;
  131. params.name("MultiSliderCtrl Text");
  132. params.rect(text_rect);
  133. params.font(p.font);
  134. params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
  135. mTextBox = LLUICtrlFactory::create<LLTextBox> (params);
  136. addChild(mTextBox);
  137. }
  138. }
  139. S32 slider_left = label_width ? label_width + multi_sliderctrl_spacing : 0;
  140. LLRect slider_rect( slider_left, top, slider_right, bottom );
  141. LLMultiSlider::Params params;
  142. params.sliders = p.sliders;
  143. params.rect(slider_rect);
  144. params.commit_callback.function( LLMultiSliderCtrl::onSliderCommit );
  145. params.mouse_down_callback( p.mouse_down_callback );
  146. params.mouse_up_callback( p.mouse_up_callback );
  147. params.initial_value(p.initial_value());
  148. params.min_value(p.min_value);
  149. params.max_value(p.max_value);
  150. params.increment(p.increment);
  151. params.max_sliders(p.max_sliders);
  152. params.allow_overlap(p.allow_overlap);
  153. params.draw_track(p.draw_track);
  154. params.use_triangle(p.use_triangle);
  155. params.control_name(p.control_name);
  156. mMultiSlider = LLUICtrlFactory::create<LLMultiSlider> (params);
  157. addChild( mMultiSlider );
  158. mCurValue = mMultiSlider->getCurSliderValue();
  159. updateText();
  160. }
  161. LLMultiSliderCtrl::~LLMultiSliderCtrl()
  162. {
  163. // Children all cleaned up by default view destructor.
  164. }
  165. // static
  166. void LLMultiSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
  167. {
  168. LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
  169. llassert( caller == self->mEditor );
  170. self->onFocusReceived();
  171. }
  172. void LLMultiSliderCtrl::setValue(const LLSD& value)
  173. {
  174. mMultiSlider->setValue(value);
  175. mCurValue = mMultiSlider->getCurSliderValue();
  176. updateText();
  177. }
  178. void LLMultiSliderCtrl::setSliderValue(const std::string& name, F32 v, BOOL from_event)
  179. {
  180. mMultiSlider->setSliderValue(name, v, from_event );
  181. mCurValue = mMultiSlider->getCurSliderValue();
  182. updateText();
  183. }
  184. void LLMultiSliderCtrl::setCurSlider(const std::string& name)
  185. {
  186. mMultiSlider->setCurSlider(name);
  187. mCurValue = mMultiSlider->getCurSliderValue();
  188. }
  189. BOOL LLMultiSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text )
  190. {
  191. BOOL res = FALSE;
  192. if (mLabelBox)
  193. {
  194. res = mLabelBox->setTextArg(key, text);
  195. if (res && mLabelWidth == 0)
  196. {
  197. S32 label_width = mFont->getWidth(mLabelBox->getText());
  198. LLRect rect = mLabelBox->getRect();
  199. S32 prev_right = rect.mRight;
  200. rect.mRight = rect.mLeft + label_width;
  201. mLabelBox->setRect(rect);
  202. S32 delta = rect.mRight - prev_right;
  203. rect = mMultiSlider->getRect();
  204. S32 left = rect.mLeft + delta;
  205. static LLUICachedControl<S32> multi_slider_ctrl_spacing ("UIMultiSliderctrlSpacing", 0);
  206. left = llclamp(left, 0, rect.mRight - multi_slider_ctrl_spacing);
  207. rect.mLeft = left;
  208. mMultiSlider->setRect(rect);
  209. }
  210. }
  211. return res;
  212. }
  213. const std::string& LLMultiSliderCtrl::addSlider()
  214. {
  215. const std::string& name = mMultiSlider->addSlider();
  216. // if it returns null, pass it on
  217. if(name == LLStringUtil::null) {
  218. return LLStringUtil::null;
  219. }
  220. // otherwise, update stuff
  221. mCurValue = mMultiSlider->getCurSliderValue();
  222. updateText();
  223. return name;
  224. }
  225. const std::string& LLMultiSliderCtrl::addSlider(F32 val)
  226. {
  227. const std::string& name = mMultiSlider->addSlider(val);
  228. // if it returns null, pass it on
  229. if(name == LLStringUtil::null) {
  230. return LLStringUtil::null;
  231. }
  232. // otherwise, update stuff
  233. mCurValue = mMultiSlider->getCurSliderValue();
  234. updateText();
  235. return name;
  236. }
  237. void LLMultiSliderCtrl::deleteSlider(const std::string& name)
  238. {
  239. mMultiSlider->deleteSlider(name);
  240. mCurValue = mMultiSlider->getCurSliderValue();
  241. updateText();
  242. }
  243. void LLMultiSliderCtrl::clear()
  244. {
  245. setCurSliderValue(0.0f);
  246. if( mEditor )
  247. {
  248. mEditor->setText(std::string(""));
  249. }
  250. if( mTextBox )
  251. {
  252. mTextBox->setText(std::string(""));
  253. }
  254. // get rid of sliders
  255. mMultiSlider->clear();
  256. }
  257. BOOL LLMultiSliderCtrl::isMouseHeldDown()
  258. {
  259. return gFocusMgr.getMouseCapture() == mMultiSlider;
  260. }
  261. void LLMultiSliderCtrl::updateText()
  262. {
  263. if( mEditor || mTextBox )
  264. {
  265. LLLocale locale(LLLocale::USER_LOCALE);
  266. // Don't display very small negative values as -0.000
  267. F32 displayed_value = (F32)(floor(getCurSliderValue() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision));
  268. std::string format = llformat("%%.%df", mPrecision);
  269. std::string text = llformat(format.c_str(), displayed_value);
  270. if( mEditor )
  271. {
  272. mEditor->setText( text );
  273. }
  274. else
  275. {
  276. mTextBox->setText( text );
  277. }
  278. }
  279. }
  280. // static
  281. void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata)
  282. {
  283. llassert(ctrl);
  284. if (!ctrl)
  285. return;
  286. LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent());
  287. llassert(self);
  288. if (!self) // cast failed - wrong type! :O
  289. return;
  290. BOOL success = FALSE;
  291. F32 val = self->mCurValue;
  292. F32 saved_val = self->mCurValue;
  293. std::string text = self->mEditor->getText();
  294. if( LLLineEditor::postvalidateFloat( text ) )
  295. {
  296. LLLocale locale(LLLocale::USER_LOCALE);
  297. val = (F32) atof( text.c_str() );
  298. if( self->mMultiSlider->getMinValue() <= val && val <= self->mMultiSlider->getMaxValue() )
  299. {
  300. self->setCurSliderValue( val ); // set the value temporarily so that the callback can retrieve it.
  301. if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) )
  302. {
  303. success = TRUE;
  304. }
  305. }
  306. }
  307. if( success )
  308. {
  309. self->onCommit();
  310. }
  311. else
  312. {
  313. if( self->getCurSliderValue() != saved_val )
  314. {
  315. self->setCurSliderValue( saved_val );
  316. }
  317. self->reportInvalidData();
  318. }
  319. self->updateText();
  320. }
  321. // static
  322. void LLMultiSliderCtrl::onSliderCommit(LLUICtrl* ctrl, const LLSD& userdata)
  323. {
  324. LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent());
  325. if (!self)
  326. return;
  327. BOOL success = FALSE;
  328. F32 saved_val = self->mCurValue;
  329. F32 new_val = self->mMultiSlider->getCurSliderValue();
  330. self->mCurValue = new_val; // set the value temporarily so that the callback can retrieve it.
  331. if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) )
  332. {
  333. success = TRUE;
  334. }
  335. if( success )
  336. {
  337. self->onCommit();
  338. }
  339. else
  340. {
  341. if( self->mCurValue != saved_val )
  342. {
  343. self->setCurSliderValue( saved_val );
  344. }
  345. self->reportInvalidData();
  346. }
  347. self->updateText();
  348. }
  349. void LLMultiSliderCtrl::setEnabled(BOOL b)
  350. {
  351. LLF32UICtrl::setEnabled( b );
  352. if( mLabelBox )
  353. {
  354. mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
  355. }
  356. mMultiSlider->setEnabled( b );
  357. if( mEditor )
  358. {
  359. mEditor->setEnabled( b );
  360. }
  361. if( mTextBox )
  362. {
  363. mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
  364. }
  365. }
  366. void LLMultiSliderCtrl::setTentative(BOOL b)
  367. {
  368. if( mEditor )
  369. {
  370. mEditor->setTentative(b);
  371. }
  372. LLF32UICtrl::setTentative(b);
  373. }
  374. void LLMultiSliderCtrl::onCommit()
  375. {
  376. setTentative(FALSE);
  377. if( mEditor )
  378. {
  379. mEditor->setTentative(FALSE);
  380. }
  381. setControlValue(getValueF32());
  382. LLF32UICtrl::onCommit();
  383. }
  384. void LLMultiSliderCtrl::setPrecision(S32 precision)
  385. {
  386. if (precision < 0 || precision > 10)
  387. {
  388. llerrs << "LLMultiSliderCtrl::setPrecision - precision out of range" << llendl;
  389. return;
  390. }
  391. mPrecision = precision;
  392. updateText();
  393. }
  394. boost::signals2::connection LLMultiSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
  395. {
  396. return mMultiSlider->setMouseDownCallback( cb );
  397. }
  398. boost::signals2::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
  399. {
  400. return mMultiSlider->setMouseUpCallback( cb );
  401. }
  402. void LLMultiSliderCtrl::onTabInto()
  403. {
  404. if( mEditor )
  405. {
  406. mEditor->onTabInto();
  407. }
  408. }
  409. void LLMultiSliderCtrl::reportInvalidData()
  410. {
  411. make_ui_sound("UISndBadKeystroke");
  412. }
  413. // virtual
  414. void LLMultiSliderCtrl::setControlName(const std::string& control_name, LLView* context)
  415. {
  416. mMultiSlider->setControlName(control_name, context);
  417. }