llspinctrl.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:11k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llspinctrl.cpp
  3.  * @brief LLSpinCtrl base class
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, 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.  
  34. #include "llspinctrl.h"
  35. #include "llgl.h"
  36. #include "llui.h"
  37. #include "lluiconstants.h"
  38. #include "llstring.h"
  39. #include "llfontgl.h"
  40. #include "lllineeditor.h"
  41. #include "llbutton.h"
  42. #include "lltextbox.h"
  43. #include "llkeyboard.h"
  44. #include "llmath.h"
  45. #include "llcontrol.h"
  46. #include "llfocusmgr.h"
  47. #include "llresmgr.h"
  48. #include "lluictrlfactory.h"
  49. const U32 MAX_STRING_LENGTH = 32;
  50. static LLDefaultChildRegistry::Register<LLSpinCtrl> r2("spinner");
  51. LLSpinCtrl::Params::Params()
  52. : label_width("label_width"),
  53. decimal_digits("decimal_digits"),
  54. allow_text_entry("allow_text_entry", true),
  55. text_enabled_color("text_enabled_color"),
  56. text_disabled_color("text_disabled_color"),
  57. up_button("up_button"),
  58. down_button("down_button")
  59. {}
  60. LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
  61. : LLF32UICtrl(p),
  62. mLabelBox(NULL),
  63. mbHasBeenSet( FALSE ),
  64. mPrecision(p.decimal_digits),
  65. mTextEnabledColor(p.text_enabled_color()),
  66. mTextDisabledColor(p.text_disabled_color())
  67. {
  68. static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0);
  69. static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0);
  70. static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0);
  71. S32 centered_top = getRect().getHeight();
  72. S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height;
  73. S32 btn_left = 0;
  74. // reserve space for spinner
  75. S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40));
  76. // Label
  77. if( !p.label().empty() )
  78. {
  79. LLRect label_rect( 0, centered_top, label_width, centered_bottom );
  80. LLTextBox::Params params;
  81. params.name("SpinCtrl Label");
  82. params.rect(label_rect);
  83. params.initial_value(p.label());
  84. if (p.font.isProvided())
  85. {
  86. params.font(p.font);
  87. }
  88. mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
  89. addChild(mLabelBox);
  90. btn_left += label_rect.mRight + spinctrl_spacing;
  91. }
  92. S32 btn_right = btn_left + spinctrl_btn_width;
  93. // Spin buttons
  94. LLButton::Params up_button_params(p.up_button);
  95. up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height);
  96. up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
  97. up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
  98. mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
  99. addChild(mUpBtn);
  100. LLButton::Params down_button_params(p.down_button);
  101. down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height);
  102. down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
  103. down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
  104. mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
  105. addChild(mDownBtn);
  106. LLRect editor_rect( btn_right + 1, centered_top, getRect().getWidth(), centered_bottom );
  107. LLLineEditor::Params params;
  108. params.name("SpinCtrl Editor");
  109. params.rect(editor_rect);
  110. if (p.font.isProvided())
  111. {
  112. params.font(p.font);
  113. }
  114. params.max_length_bytes(MAX_STRING_LENGTH);
  115. params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2)));
  116. params.prevalidate_callback(&LLTextValidate::validateFloat);
  117. params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
  118. mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
  119. mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this ));
  120. //RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus
  121. // than when it doesn't.  Instead, if you always have to double click to select all the text, 
  122. // it's easier to understand
  123. //mEditor->setSelectAllonFocusReceived(TRUE);
  124. addChild(mEditor);
  125. updateEditor();
  126. setUseBoundingRect( TRUE );
  127. }
  128. F32 clamp_precision(F32 value, S32 decimal_precision)
  129. {
  130. // pow() isn't perfect
  131. F64 clamped_value = value;
  132. for (S32 i = 0; i < decimal_precision; i++)
  133. clamped_value *= 10.0;
  134. clamped_value = llround((F32)clamped_value);
  135. for (S32 i = 0; i < decimal_precision; i++)
  136. clamped_value /= 10.0;
  137. return (F32)clamped_value;
  138. }
  139. void LLSpinCtrl::onUpBtn( const LLSD& data )
  140. {
  141. if( getEnabled() )
  142. {
  143. std::string text = mEditor->getText();
  144. if( LLLineEditor::postvalidateFloat( text ) )
  145. {
  146. LLLocale locale(LLLocale::USER_LOCALE);
  147. F32 cur_val = (F32) atof(text.c_str());
  148. // use getValue()/setValue() to force reload from/to control
  149. F32 val = cur_val + mIncrement;
  150. val = clamp_precision(val, mPrecision);
  151. val = llmin( val, mMaxValue );
  152. if (val < mMinValue) val = mMinValue;
  153. if (val > mMaxValue) val = mMaxValue;
  154. F32 saved_val = (F32)getValue().asReal();
  155. setValue(val);
  156. if( mValidateSignal && !(*mValidateSignal)( this, val ) )
  157. {
  158. setValue( saved_val );
  159. reportInvalidData();
  160. updateEditor();
  161. return;
  162. }
  163. updateEditor();
  164. onCommit();
  165. }
  166. }
  167. }
  168. void LLSpinCtrl::onDownBtn( const LLSD& data )
  169. {
  170. if( getEnabled() )
  171. {
  172. std::string text = mEditor->getText();
  173. if( LLLineEditor::postvalidateFloat( text ) )
  174. {
  175. LLLocale locale(LLLocale::USER_LOCALE);
  176. F32 cur_val = (F32) atof(text.c_str());
  177. F32 val = cur_val - mIncrement;
  178. val = clamp_precision(val, mPrecision);
  179. val = llmax( val, mMinValue );
  180. if (val < mMinValue) val = mMinValue;
  181. if (val > mMaxValue) val = mMaxValue;
  182. F32 saved_val = (F32)getValue().asReal();
  183. setValue(val);
  184. if( mValidateSignal && !(*mValidateSignal)( this, val ) )
  185. {
  186. setValue( saved_val );
  187. reportInvalidData();
  188. updateEditor();
  189. return;
  190. }
  191. updateEditor();
  192. onCommit();
  193. }
  194. }
  195. }
  196. // static
  197. void LLSpinCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
  198. {
  199. LLSpinCtrl* self = (LLSpinCtrl*) userdata;
  200. llassert( caller == self->mEditor );
  201. self->onFocusReceived();
  202. }
  203. void LLSpinCtrl::setValue(const LLSD& value )
  204. {
  205. F32 v = (F32)value.asReal();
  206. if (getValueF32() != v || !mbHasBeenSet)
  207. {
  208. mbHasBeenSet = TRUE;
  209.         LLF32UICtrl::setValue(value);
  210. if (!mEditor->hasFocus())
  211. {
  212. updateEditor();
  213. }
  214. }
  215. }
  216. //no matter if Editor has the focus, update the value
  217. void LLSpinCtrl::forceSetValue(const LLSD& value )
  218. {
  219. F32 v = (F32)value.asReal();
  220. if (getValueF32() != v || !mbHasBeenSet)
  221. {
  222. mbHasBeenSet = TRUE;
  223.         LLF32UICtrl::setValue(value);
  224. updateEditor();
  225. }
  226. }
  227. void LLSpinCtrl::clear()
  228. {
  229. setValue(mMinValue);
  230. mEditor->clear();
  231. mbHasBeenSet = FALSE;
  232. }
  233. void LLSpinCtrl::updateLabelColor()
  234. {
  235. if( mLabelBox )
  236. {
  237. mLabelBox->setColor( getEnabled() ? mTextEnabledColor.get() : mTextDisabledColor.get() );
  238. }
  239. }
  240. void LLSpinCtrl::updateEditor()
  241. {
  242. LLLocale locale(LLLocale::USER_LOCALE);
  243. // Don't display very small negative valu es as -0.000
  244. F32 displayed_value = clamp_precision((F32)getValue().asReal(), mPrecision);
  245. // if( S32( displayed_value * pow( 10, mPrecision ) ) == 0 )
  246. // {
  247. // displayed_value = 0.f;
  248. // }
  249. std::string format = llformat("%%.%df", mPrecision);
  250. std::string text = llformat(format.c_str(), displayed_value);
  251. mEditor->setText( text );
  252. }
  253. void LLSpinCtrl::onEditorCommit( const LLSD& data )
  254. {
  255. BOOL success = FALSE;
  256. std::string text = mEditor->getText();
  257. if( LLLineEditor::postvalidateFloat( text ) )
  258. {
  259. LLLocale locale(LLLocale::USER_LOCALE);
  260. F32 val = (F32) atof(text.c_str());
  261. if (val < mMinValue) val = mMinValue;
  262. if (val > mMaxValue) val = mMaxValue;
  263. F32 saved_val = getValueF32();
  264. setValue(val);
  265. if( !mValidateSignal || (*mValidateSignal)( this, val ) )
  266. {
  267. success = TRUE;
  268. onCommit();
  269. }
  270. else
  271. {
  272. setValue(saved_val);
  273. }
  274. }
  275. updateEditor();
  276. if( !success )
  277. {
  278. reportInvalidData();
  279. }
  280. }
  281. void LLSpinCtrl::forceEditorCommit()
  282. {
  283. onEditorCommit( LLSD() );
  284. }
  285. void LLSpinCtrl::setFocus(BOOL b)
  286. {
  287. LLUICtrl::setFocus( b );
  288. mEditor->setFocus( b );
  289. }
  290. void LLSpinCtrl::setEnabled(BOOL b)
  291. {
  292. LLView::setEnabled( b );
  293. mEditor->setEnabled( b );
  294. updateLabelColor();
  295. }
  296. void LLSpinCtrl::setTentative(BOOL b)
  297. {
  298. mEditor->setTentative(b);
  299. LLUICtrl::setTentative(b);
  300. }
  301. BOOL LLSpinCtrl::isMouseHeldDown() const
  302. {
  303. return 
  304. mDownBtn->hasMouseCapture()
  305. || mUpBtn->hasMouseCapture();
  306. }
  307. void LLSpinCtrl::onCommit()
  308. {
  309. setTentative(FALSE);
  310. setControlValue(getValueF32());
  311. LLF32UICtrl::onCommit();
  312. }
  313. void LLSpinCtrl::setPrecision(S32 precision)
  314. {
  315. if (precision < 0 || precision > 10)
  316. {
  317. llerrs << "LLSpinCtrl::setPrecision - precision out of range" << llendl;
  318. return;
  319. }
  320. mPrecision = precision;
  321. updateEditor();
  322. }
  323. void LLSpinCtrl::setLabel(const LLStringExplicit& label)
  324. {
  325. if (mLabelBox)
  326. {
  327. mLabelBox->setText(label);
  328. }
  329. else
  330. {
  331. llwarns << "Attempting to set label on LLSpinCtrl constructed without one " << getName() << llendl;
  332. }
  333. updateLabelColor();
  334. }
  335. void LLSpinCtrl::setAllowEdit(BOOL allow_edit)
  336. {
  337. mEditor->setEnabled(allow_edit);
  338. mAllowEdit = allow_edit;
  339. }
  340. void LLSpinCtrl::onTabInto()
  341. {
  342. mEditor->onTabInto(); 
  343. }
  344. void LLSpinCtrl::reportInvalidData()
  345. {
  346. make_ui_sound("UISndBadKeystroke");
  347. }
  348. BOOL LLSpinCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
  349. {
  350. if( clicks > 0 )
  351. {
  352. while( clicks-- )
  353. {
  354. onDownBtn(getValue());
  355. }
  356. }
  357. else
  358. while( clicks++ )
  359. {
  360. onUpBtn(getValue());
  361. }
  362. return TRUE;
  363. }
  364. BOOL LLSpinCtrl::handleKeyHere(KEY key, MASK mask)
  365. {
  366. if (mEditor->hasFocus())
  367. {
  368. if(key == KEY_ESCAPE)
  369. {
  370. // text editors don't support revert normally (due to user confusion)
  371. // but not allowing revert on a spinner seems dangerous
  372. updateEditor();
  373. mEditor->setFocus(FALSE);
  374. return TRUE;
  375. }
  376. if(key == KEY_UP)
  377. {
  378. onUpBtn(getValue());
  379. return TRUE;
  380. }
  381. if(key == KEY_DOWN)
  382. {
  383. onDownBtn(getValue());
  384. return TRUE;
  385. }
  386. }
  387. return FALSE;
  388. }