PageRenderTime 28ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llui/llsliderctrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 436 lines | 338 code | 60 blank | 38 comment | 57 complexity | e95161518ac6266b60a26daf426fc88c MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llsliderctrl.cpp
  3. * @brief LLSliderCtrl base class
  4. *
  5. * $LicenseInfo:firstyear=2002&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 "llsliderctrl.h"
  28. #include "llmath.h"
  29. #include "llfontgl.h"
  30. #include "llgl.h"
  31. #include "llkeyboard.h"
  32. #include "lllineeditor.h"
  33. #include "llslider.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. const U32 MAX_STRING_LENGTH = 10;
  43. static LLDefaultChildRegistry::Register<LLSliderCtrl> r("slider");
  44. LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)
  45. : LLF32UICtrl(p),
  46. mLabelBox( NULL ),
  47. mEditor( NULL ),
  48. mTextBox( NULL ),
  49. mFont(p.font),
  50. mShowText(p.show_text),
  51. mCanEditText(p.can_edit_text),
  52. mPrecision(p.decimal_digits),
  53. mTextEnabledColor(p.text_color()),
  54. mTextDisabledColor(p.text_disabled_color()),
  55. mLabelWidth(p.label_width)
  56. {
  57. S32 top = getRect().getHeight();
  58. S32 bottom = 0;
  59. S32 left = 0;
  60. S32 label_width = p.label_width;
  61. S32 text_width = p.text_width;
  62. // Label
  63. if( !p.label().empty() )
  64. {
  65. if (!p.label_width.isProvided())
  66. {
  67. label_width = p.font()->getWidth(p.label);
  68. }
  69. LLRect label_rect( left, top, label_width, bottom );
  70. LLTextBox::Params params(p.slider_label);
  71. if (!params.rect.isProvided())
  72. {
  73. params.rect = label_rect;
  74. }
  75. if (!params.font.isProvided())
  76. {
  77. params.font = p.font;
  78. }
  79. params.initial_value(p.label());
  80. mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
  81. addChild(mLabelBox);
  82. mLabelFont = params.font();
  83. }
  84. if (p.show_text && !p.text_width.isProvided())
  85. {
  86. // calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
  87. if ( p.max_value )
  88. text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10 ( p.max_value ) ) + p.decimal_digits + 1 );
  89. if ( p.increment < 1.0f )
  90. text_width += p.font()->getWidth(std::string(".")); // (mostly) take account of decimal point in value
  91. if ( p.min_value < 0.0f || p.max_value < 0.0f )
  92. text_width += p.font()->getWidth(std::string("-")); // (mostly) take account of minus sign
  93. // padding to make things look nicer
  94. text_width += 8;
  95. }
  96. S32 text_left = getRect().getWidth() - text_width;
  97. static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0);
  98. S32 slider_right = getRect().getWidth();
  99. if( p.show_text )
  100. {
  101. slider_right = text_left - sliderctrl_spacing;
  102. }
  103. S32 slider_left = label_width ? label_width + sliderctrl_spacing : 0;
  104. LLSlider::Params slider_p(p.slider_bar);
  105. slider_p.name("slider_bar");
  106. if (!slider_p.rect.isProvided())
  107. {
  108. slider_p.rect = LLRect(slider_left,top,slider_right,bottom);
  109. }
  110. if (!slider_p.initial_value.isProvided())
  111. {
  112. slider_p.initial_value = p.initial_value().asReal();
  113. }
  114. if (!slider_p.min_value.isProvided())
  115. {
  116. slider_p.min_value = p.min_value;
  117. }
  118. if (!slider_p.max_value.isProvided())
  119. {
  120. slider_p.max_value = p.max_value;
  121. }
  122. if (!slider_p.increment.isProvided())
  123. {
  124. slider_p.increment = p.increment;
  125. }
  126. if (!slider_p.orientation.isProvided())
  127. {
  128. slider_p.orientation = p.orientation;
  129. }
  130. slider_p.commit_callback.function = &LLSliderCtrl::onSliderCommit;
  131. slider_p.control_name = p.control_name;
  132. slider_p.mouse_down_callback( p.mouse_down_callback );
  133. slider_p.mouse_up_callback( p.mouse_up_callback );
  134. mSlider = LLUICtrlFactory::create<LLSlider> (slider_p);
  135. addChild( mSlider );
  136. if( p.show_text() )
  137. {
  138. LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
  139. if( p.can_edit_text() )
  140. {
  141. LLLineEditor::Params line_p(p.value_editor);
  142. if (!line_p.rect.isProvided())
  143. {
  144. line_p.rect = text_rect;
  145. }
  146. if (!line_p.font.isProvided())
  147. {
  148. line_p.font = p.font;
  149. }
  150. line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit);
  151. line_p.prevalidate_callback(&LLTextValidate::validateFloat);
  152. mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p);
  153. mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this ));
  154. // don't do this, as selecting the entire text is single clicking in some cases
  155. // and double clicking in others
  156. //mEditor->setSelectAllonFocusReceived(TRUE);
  157. addChild(mEditor);
  158. }
  159. else
  160. {
  161. LLTextBox::Params text_p(p.value_text);
  162. if (!text_p.rect.isProvided())
  163. {
  164. text_p.rect = text_rect;
  165. }
  166. if (!text_p.font.isProvided())
  167. {
  168. text_p.font = p.font;
  169. }
  170. mTextBox = LLUICtrlFactory::create<LLTextBox>(text_p);
  171. addChild(mTextBox);
  172. }
  173. }
  174. updateText();
  175. }
  176. // static
  177. void LLSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
  178. {
  179. LLSliderCtrl* self = (LLSliderCtrl*) userdata;
  180. llassert( caller == self->mEditor );
  181. self->onFocusReceived();
  182. }
  183. void LLSliderCtrl::setValue(F32 v, BOOL from_event)
  184. {
  185. mSlider->setValue( v, from_event );
  186. mValue = mSlider->getValueF32();
  187. updateText();
  188. }
  189. BOOL LLSliderCtrl::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 && mLabelFont && mLabelWidth == 0)
  196. {
  197. S32 label_width = mLabelFont->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 = mSlider->getRect();
  204. S32 left = rect.mLeft + delta;
  205. static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0);
  206. left = llclamp(left, 0, rect.mRight - sliderctrl_spacing);
  207. rect.mLeft = left;
  208. mSlider->setRect(rect);
  209. }
  210. }
  211. return res;
  212. }
  213. void LLSliderCtrl::clear()
  214. {
  215. setValue(0.0f);
  216. if( mEditor )
  217. {
  218. mEditor->setText( LLStringUtil::null );
  219. }
  220. if( mTextBox )
  221. {
  222. mTextBox->setText( LLStringUtil::null );
  223. }
  224. }
  225. void LLSliderCtrl::updateText()
  226. {
  227. if( mEditor || mTextBox )
  228. {
  229. LLLocale locale(LLLocale::USER_LOCALE);
  230. // Don't display very small negative values as -0.000
  231. F32 displayed_value = (F32)(floor(getValueF32() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision));
  232. std::string format = llformat("%%.%df", mPrecision);
  233. std::string text = llformat(format.c_str(), displayed_value);
  234. if( mEditor )
  235. {
  236. // Setting editor text here to "" before using actual text is here because if text which
  237. // is set is the same as the one which is actually typed into lineeditor, LLLineEditor::setText()
  238. // will exit at it's beginning, so text for revert on escape won't be saved. (EXT-8536)
  239. mEditor->setText( LLStringUtil::null );
  240. mEditor->setText( text );
  241. }
  242. else
  243. {
  244. mTextBox->setText( text );
  245. }
  246. }
  247. }
  248. // static
  249. void LLSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata )
  250. {
  251. LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent());
  252. if (!self)
  253. return;
  254. BOOL success = FALSE;
  255. F32 val = self->mValue;
  256. F32 saved_val = self->mValue;
  257. std::string text = self->mEditor->getText();
  258. if( LLLineEditor::postvalidateFloat( text ) )
  259. {
  260. LLLocale locale(LLLocale::USER_LOCALE);
  261. val = (F32) atof( text.c_str() );
  262. if( self->mSlider->getMinValue() <= val && val <= self->mSlider->getMaxValue() )
  263. {
  264. self->setValue( val ); // set the value temporarily so that the callback can retrieve it.
  265. if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) )
  266. {
  267. success = TRUE;
  268. }
  269. }
  270. }
  271. if( success )
  272. {
  273. self->onCommit();
  274. }
  275. else
  276. {
  277. if( self->getValueF32() != saved_val )
  278. {
  279. self->setValue( saved_val );
  280. }
  281. self->reportInvalidData();
  282. }
  283. self->updateText();
  284. }
  285. // static
  286. void LLSliderCtrl::onSliderCommit( LLUICtrl* ctrl, const LLSD& userdata )
  287. {
  288. LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent());
  289. if (!self)
  290. return;
  291. BOOL success = FALSE;
  292. F32 saved_val = self->mValue;
  293. F32 new_val = self->mSlider->getValueF32();
  294. self->mValue = new_val; // set the value temporarily so that the callback can retrieve it.
  295. if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) )
  296. {
  297. success = TRUE;
  298. }
  299. if( success )
  300. {
  301. self->onCommit();
  302. }
  303. else
  304. {
  305. if( self->mValue != saved_val )
  306. {
  307. self->setValue( saved_val );
  308. }
  309. self->reportInvalidData();
  310. }
  311. self->updateText();
  312. }
  313. void LLSliderCtrl::setEnabled(BOOL b)
  314. {
  315. LLView::setEnabled( b );
  316. if( mLabelBox )
  317. {
  318. mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
  319. }
  320. mSlider->setEnabled( b );
  321. if( mEditor )
  322. {
  323. mEditor->setEnabled( b );
  324. }
  325. if( mTextBox )
  326. {
  327. mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
  328. }
  329. }
  330. void LLSliderCtrl::setTentative(BOOL b)
  331. {
  332. if( mEditor )
  333. {
  334. mEditor->setTentative(b);
  335. }
  336. LLF32UICtrl::setTentative(b);
  337. }
  338. void LLSliderCtrl::onCommit()
  339. {
  340. setTentative(FALSE);
  341. if( mEditor )
  342. {
  343. mEditor->setTentative(FALSE);
  344. }
  345. setControlValue(getValueF32());
  346. LLF32UICtrl::onCommit();
  347. }
  348. void LLSliderCtrl::setPrecision(S32 precision)
  349. {
  350. if (precision < 0 || precision > 10)
  351. {
  352. llerrs << "LLSliderCtrl::setPrecision - precision out of range" << llendl;
  353. return;
  354. }
  355. mPrecision = precision;
  356. updateText();
  357. }
  358. boost::signals2::connection LLSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
  359. {
  360. return mSlider->setMouseDownCallback( cb );
  361. }
  362. boost::signals2::connection LLSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
  363. {
  364. return mSlider->setMouseUpCallback( cb );
  365. }
  366. void LLSliderCtrl::onTabInto()
  367. {
  368. if( mEditor )
  369. {
  370. mEditor->onTabInto();
  371. }
  372. }
  373. void LLSliderCtrl::reportInvalidData()
  374. {
  375. make_ui_sound("UISndBadKeystroke");
  376. }