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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llradiogroup.cpp
  3.  * @brief LLRadioGroup 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. #include "llboost.h"
  34. #include "llradiogroup.h"
  35. #include "indra_constants.h"
  36. #include "llviewborder.h"
  37. #include "llcontrol.h"
  38. #include "llui.h"
  39. #include "llfocusmgr.h"
  40. #include "lluictrlfactory.h"
  41. #include "llsdutil.h"
  42. static LLDefaultChildRegistry::Register<LLRadioGroup> r1("radio_group");
  43. /*
  44.  * An invisible view containing multiple mutually exclusive toggling 
  45.  * buttons (usually radio buttons).  Automatically handles the mutex
  46.  * condition by highlighting only one button at a time.
  47.  */
  48. class LLRadioCtrl : public LLCheckBoxCtrl 
  49. {
  50. public:
  51. typedef LLRadioGroup::ItemParams Params;
  52. /*virtual*/ ~LLRadioCtrl();
  53. /*virtual*/ void setValue(const LLSD& value);
  54. /*virtual*/ BOOL postBuild();
  55. LLSD getPayload() { return mPayload; }
  56. // Ensure label is in an attribute, not the contents
  57. static void setupParamsForExport(Params& p, LLView* parent);
  58. protected:
  59. LLRadioCtrl(const LLRadioGroup::ItemParams& p);
  60. friend class LLUICtrlFactory;
  61. LLSD mPayload; // stores data that this item represents in the radio group
  62. };
  63. static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item");
  64. LLRadioGroup::Params::Params()
  65. : has_border("draw_border"),
  66. items("item") 
  67. {
  68. addSynonym(items, "radio_item");
  69. name = "radio_group";
  70. mouse_opaque = true;
  71. follows.flags = FOLLOWS_LEFT | FOLLOWS_TOP;
  72. // radio items are not tabbable until they are selected
  73. tab_stop = false;
  74. }
  75. LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)
  76. : LLUICtrl(p),
  77. mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
  78. mSelectedIndex(-1),
  79. mHasBorder(p.has_border)
  80. {
  81. if (mHasBorder)
  82. {
  83. LLViewBorder::Params params;
  84. params.name("radio group border");
  85. params.rect(LLRect(0, getRect().getHeight(), getRect().getWidth(), 0));
  86. params.bevel_style(LLViewBorder::BEVEL_NONE);
  87. LLViewBorder * vb = LLUICtrlFactory::create<LLViewBorder> (params);
  88. addChild (vb);
  89. }
  90. }
  91. void LLRadioGroup::initFromParams(const Params& p)
  92. {
  93. LLUICtrl::initFromParams(p);
  94. for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
  95. it != p.items().end();
  96. ++it)
  97. {
  98. LLRadioGroup::ItemParams item_params(*it);
  99. item_params.font.setIfNotProvided(mFont); // apply radio group font by default
  100. item_params.commit_callback.function = boost::bind(&LLRadioGroup::onClickButton, this, _1);
  101. item_params.from_xui = p.from_xui;
  102. if (p.from_xui)
  103. {
  104. applyXUILayout(item_params, this);
  105. }
  106. LLRadioCtrl* item = LLUICtrlFactory::create<LLRadioCtrl>(item_params, this);
  107. mRadioButtons.push_back(item);
  108. }
  109. }
  110. LLRadioGroup::~LLRadioGroup()
  111. {
  112. }
  113. // virtual
  114. BOOL LLRadioGroup::postBuild()
  115. {
  116. if (!mRadioButtons.empty())
  117. {
  118. mRadioButtons[0]->setTabStop(true);
  119. }
  120. if (mControlVariable)
  121. {
  122. setSelectedIndex(mControlVariable->getValue().asInteger());
  123. }
  124. return TRUE;
  125. }
  126. void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled)
  127. {
  128. S32 count = 0;
  129. for (button_list_t::iterator iter = mRadioButtons.begin();
  130.  iter != mRadioButtons.end(); ++iter)
  131. {
  132. LLRadioCtrl* child = *iter;
  133. if (count == index)
  134. {
  135. child->setEnabled(enabled);
  136. if (index == mSelectedIndex && enabled == FALSE)
  137. {
  138. setSelectedIndex(-1);
  139. }
  140. break;
  141. }
  142. count++;
  143. }
  144. count = 0;
  145. if (mSelectedIndex < 0)
  146. {
  147. // Set to highest enabled value < index,
  148. // or lowest value above index if none lower are enabled
  149. // or 0 if none are enabled
  150. for (button_list_t::iterator iter = mRadioButtons.begin();
  151.  iter != mRadioButtons.end(); ++iter)
  152. {
  153. LLRadioCtrl* child = *iter;
  154. if (count >= index && mSelectedIndex >= 0)
  155. {
  156. break;
  157. }
  158. if (child->getEnabled())
  159. {
  160. setSelectedIndex(count);
  161. }
  162. count++;
  163. }
  164. if (mSelectedIndex < 0)
  165. {
  166. setSelectedIndex(0);
  167. }
  168. }
  169. }
  170. BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
  171. {
  172. if (index < 0 || (S32)mRadioButtons.size() <= index )
  173. {
  174. return FALSE;
  175. }
  176. if (mSelectedIndex >= 0)
  177. {
  178. LLRadioCtrl* old_radio_item = mRadioButtons[mSelectedIndex];
  179. old_radio_item->setTabStop(false);
  180. old_radio_item->setValue( FALSE );
  181. }
  182. else
  183. {
  184. mRadioButtons[0]->setTabStop(false);
  185. }
  186. mSelectedIndex = index;
  187. LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex];
  188. radio_item->setTabStop(true);
  189. radio_item->setValue( TRUE );
  190. if (hasFocus())
  191. {
  192. mRadioButtons[mSelectedIndex]->focusFirstItem(FALSE, FALSE);
  193. }
  194. if (!from_event)
  195. {
  196. setControlValue(getValue());
  197. }
  198. return TRUE;
  199. }
  200. BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask)
  201. {
  202. BOOL handled = FALSE;
  203. // do any of the tab buttons have keyboard focus?
  204. if (mask == MASK_NONE)
  205. {
  206. switch(key)
  207. {
  208. case KEY_DOWN:
  209. if (!setSelectedIndex((getSelectedIndex() + 1)))
  210. {
  211. make_ui_sound("UISndInvalidOp");
  212. }
  213. else
  214. {
  215. onCommit();
  216. }
  217. handled = TRUE;
  218. break;
  219. case KEY_UP:
  220. if (!setSelectedIndex((getSelectedIndex() - 1)))
  221. {
  222. make_ui_sound("UISndInvalidOp");
  223. }
  224. else
  225. {
  226. onCommit();
  227. }
  228. handled = TRUE;
  229. break;
  230. case KEY_LEFT:
  231. if (!setSelectedIndex((getSelectedIndex() - 1)))
  232. {
  233. make_ui_sound("UISndInvalidOp");
  234. }
  235. else
  236. {
  237. onCommit();
  238. }
  239. handled = TRUE;
  240. break;
  241. case KEY_RIGHT:
  242. if (!setSelectedIndex((getSelectedIndex() + 1)))
  243. {
  244. make_ui_sound("UISndInvalidOp");
  245. }
  246. else
  247. {
  248. onCommit();
  249. }
  250. handled = TRUE;
  251. break;
  252. default:
  253. break;
  254. }
  255. }
  256. return handled;
  257. }
  258. BOOL LLRadioGroup::handleMouseDown(S32 x, S32 y, MASK mask)
  259. {
  260. // grab focus preemptively, before child button takes mousecapture
  261. // 
  262. if (hasTabStop())
  263. {
  264. focusFirstItem(FALSE, FALSE);
  265. }
  266. return LLUICtrl::handleMouseDown(x, y, mask);
  267. }
  268. // Handle one button being clicked.  All child buttons must have this
  269. // function as their callback function.
  270. void LLRadioGroup::onClickButton(LLUICtrl* ctrl)
  271. {
  272. // llinfos << "LLRadioGroup::onClickButton" << llendl;
  273. LLRadioCtrl* clicked_radio = dynamic_cast<LLRadioCtrl*>(ctrl);
  274. if (!clicked_radio)
  275.     return;
  276. S32 index = 0;
  277. for (button_list_t::iterator iter = mRadioButtons.begin();
  278.  iter != mRadioButtons.end(); ++iter)
  279. {
  280. LLRadioCtrl* radio = *iter;
  281. if (radio == clicked_radio)
  282. {
  283. // llinfos << "clicked button " << index << llendl;
  284. setSelectedIndex(index);
  285. // BUG: Calls click callback even if button didn't actually change
  286. onCommit();
  287. return;
  288. }
  289. index++;
  290. }
  291. llwarns << "LLRadioGroup::onClickButton - clicked button that isn't a child" << llendl;
  292. }
  293. void LLRadioGroup::setValue( const LLSD& value )
  294. {
  295. int idx = 0;
  296. for (button_list_t::const_iterator iter = mRadioButtons.begin();
  297.  iter != mRadioButtons.end(); ++iter)
  298. {
  299. LLRadioCtrl* radio = *iter;
  300. if (radio->getPayload().asString() == value.asString())
  301. {
  302. setSelectedIndex(idx);
  303. idx = -1;
  304. break;
  305. }
  306. ++idx;
  307. }
  308. if (idx != -1)
  309. {
  310. // string not found, try integer
  311. if (value.isInteger())
  312. {
  313. setSelectedIndex((S32) value.asInteger(), TRUE);
  314. }
  315. else
  316. {
  317. llwarns << "LLRadioGroup::setValue: value not found: " << value.asString() << llendl;
  318. }
  319. }
  320. }
  321. LLSD LLRadioGroup::getValue() const
  322. {
  323. int index = getSelectedIndex();
  324. int idx = 0;
  325. for (button_list_t::const_iterator iter = mRadioButtons.begin();
  326.  iter != mRadioButtons.end(); ++iter)
  327. {
  328. if (idx == index) return LLSD((*iter)->getPayload());
  329. ++idx;
  330. }
  331. return LLSD();
  332. }
  333. // LLCtrlSelectionInterface functions
  334. BOOL LLRadioGroup::setCurrentByID( const LLUUID& id )
  335. {
  336. return FALSE;
  337. }
  338. LLUUID LLRadioGroup::getCurrentID() const
  339. {
  340. return LLUUID::null;
  341. }
  342. BOOL LLRadioGroup::setSelectedByValue(const LLSD& value, BOOL selected)
  343. {
  344. S32 idx = 0;
  345. for (button_list_t::const_iterator iter = mRadioButtons.begin();
  346.  iter != mRadioButtons.end(); ++iter)
  347. {
  348. if((*iter)->getPayload().asString() == value.asString())
  349. {
  350. setSelectedIndex(idx);
  351. return TRUE;
  352. }
  353. idx++;
  354. }
  355. return FALSE;
  356. }
  357. LLSD LLRadioGroup::getSelectedValue()
  358. {
  359. return getValue();
  360. }
  361. BOOL LLRadioGroup::isSelected(const LLSD& value) const
  362. {
  363. S32 idx = 0;
  364. for (button_list_t::const_iterator iter = mRadioButtons.begin();
  365.  iter != mRadioButtons.end(); ++iter)
  366. {
  367. if((*iter)->getPayload().asString() == value.asString())
  368. {
  369. if (idx == mSelectedIndex) 
  370. {
  371. return TRUE;
  372. }
  373. }
  374. idx++;
  375. }
  376. return FALSE;
  377. }
  378. BOOL LLRadioGroup::operateOnSelection(EOperation op)
  379. {
  380. return FALSE;
  381. }
  382. BOOL LLRadioGroup::operateOnAll(EOperation op)
  383. {
  384. return FALSE;
  385. }
  386. LLRadioGroup::ItemParams::ItemParams()
  387. : value("value")
  388. {
  389. addSynonym(value, "initial_value");
  390. }
  391. LLRadioCtrl::LLRadioCtrl(const LLRadioGroup::ItemParams& p)
  392. : LLCheckBoxCtrl(p),
  393. mPayload(p.value)
  394. {
  395. // use name as default "Value" for backwards compatibility
  396. if (!p.value.isProvided())
  397. {
  398. mPayload = p.name();
  399. }
  400. }
  401. BOOL LLRadioCtrl::postBuild()
  402. {
  403. // Old-style radio_item used the text contents to indicate the label,
  404. // but new-style radio_item uses label attribute.
  405. std::string value = getValue().asString();
  406. if (!value.empty())
  407. {
  408. setLabel(value);
  409. }
  410. return TRUE;
  411. }
  412. LLRadioCtrl::~LLRadioCtrl()
  413. {
  414. }
  415. void LLRadioCtrl::setValue(const LLSD& value)
  416. {
  417. LLCheckBoxCtrl::setValue(value);
  418. mButton->setTabStop(value.asBoolean());
  419. }
  420. // *TODO: Remove this function after the initial XUI XML re-export pass.
  421. // static
  422. void LLRadioCtrl::setupParamsForExport(Params& p, LLView* parent)
  423. {
  424. std::string label = p.label;
  425. if (label.empty())
  426. {
  427. // We don't have a label attribute, so move the text contents
  428. // stored in "value" into the label
  429. std::string initial_value = p.LLUICtrl::Params::initial_value();
  430. p.label = initial_value;
  431. p.LLUICtrl::Params::initial_value = LLSD();
  432. }
  433. LLCheckBoxCtrl::setupParamsForExport(p, parent);
  434. }