llbutton.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /**
  2. * @file llbutton.cpp
  3. * @brief LLButton base class
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-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 "llbutton.h"
  34. #include "llcriticaldamp.h"
  35. #include "llhtmlhelp.h"
  36. #include "llkeyboard.h"
  37. #include "llrender.h"
  38. #include "llwindow.h"
  39. static const std::string LL_BUTTON_TAG = "button";
  40. static LLRegisterWidget<LLButton> r01(LL_BUTTON_TAG);
  41. // Globals loaded from settings.xml
  42. S32 LLBUTTON_ORIG_H_PAD = 6; // Pre-zoomable UI
  43. S32 gButtonHPad = 10;
  44. S32 gButtonVPad = 1;
  45. S32 gBtnHeightSmall = 16;
  46. S32 gBtnHeight = 20;
  47. S32 BORDER_SIZE = 1;
  48. LLButton::LLButton(const std::string& name, const LLRect& rect,
  49. const char* control_name,
  50. void (*click_callback)(void*), void* callback_data)
  51. : LLUICtrl(name, rect, true, NULL, NULL),
  52. mClickedCallback(click_callback),
  53. mMouseHoverCallback(NULL),
  54. mMouseDownCallback(NULL),
  55. mMouseUpCallback(NULL),
  56. mHeldDownCallback(NULL),
  57. mGLFont(NULL),
  58. mMouseDownFrame(0),
  59. mHeldDownDelay(0.5f), // seconds until held-down callback is called
  60. mHeldDownFrameDelay(0),
  61. mImageUnselected(NULL),
  62. mImageSelected(NULL),
  63. mImageHoverSelected(NULL),
  64. mImageHoverUnselected(NULL),
  65. mImageDisabled(NULL),
  66. mImageDisabledSelected(NULL),
  67. mToggleState(false),
  68. mIsToggle(false),
  69. mScaleImage(true),
  70. mDropShadowedText(true),
  71. mBorderEnabled(false),
  72. mFlashing(false),
  73. mHAlign(LLFontGL::HCENTER),
  74. mLeftHPad(gButtonHPad),
  75. mRightHPad(gButtonHPad),
  76. mHoverGlowStrength(0.15f),
  77. mCurGlowStrength(0.f),
  78. mNeedsHighlight(false),
  79. mCommitOnReturn(true),
  80. mImagep(NULL)
  81. {
  82. mUnselectedLabel = name;
  83. mSelectedLabel = name;
  84. setImageUnselected("button_enabled_32x128.tga");
  85. setImageSelected("button_enabled_selected_32x128.tga");
  86. setImageDisabled("button_disabled_32x128.tga");
  87. setImageDisabledSelected("button_disabled_32x128.tga");
  88. mImageColor = LLUI::sButtonImageColor;
  89. mDisabledImageColor = LLUI::sButtonImageColor;
  90. init(click_callback, callback_data, NULL, control_name);
  91. }
  92. LLButton::LLButton(const std::string& name, const LLRect& rect,
  93. const std::string& unselected_image_name,
  94. const std::string& selected_image_name,
  95. const char* control_name,
  96. void (*click_callback)(void*), void* callback_data,
  97. const LLFontGL* font,
  98. const std::string& unselected_label,
  99. const std::string& selected_label)
  100. : LLUICtrl(name, rect, true, NULL, NULL),
  101. mClickedCallback(click_callback),
  102. mMouseHoverCallback(NULL),
  103. mMouseDownCallback(NULL),
  104. mMouseUpCallback(NULL),
  105. mHeldDownCallback(NULL),
  106. mGLFont(NULL),
  107. mMouseDownFrame(0),
  108. mHeldDownDelay(0.5f), // Seconds until held-down callback is called
  109. mHeldDownFrameDelay(0),
  110. mImageUnselected(NULL),
  111. mImageSelected(NULL),
  112. mImageHoverSelected(NULL),
  113. mImageHoverUnselected(NULL),
  114. mImageDisabled(NULL),
  115. mImageDisabledSelected(NULL),
  116. mToggleState(false),
  117. mIsToggle(false),
  118. mScaleImage(true),
  119. mDropShadowedText(true),
  120. mBorderEnabled(false),
  121. mFlashing(false),
  122. mHAlign(LLFontGL::HCENTER),
  123. mLeftHPad(gButtonHPad),
  124. mRightHPad(gButtonHPad),
  125. mHoverGlowStrength(0.25f),
  126. mCurGlowStrength(0.f),
  127. mNeedsHighlight(false),
  128. mCommitOnReturn(true),
  129. mImagep(NULL)
  130. {
  131. mUnselectedLabel = unselected_label;
  132. mSelectedLabel = selected_label;
  133. // By default, disabled color is same as enabled
  134. mImageColor = LLUI::sButtonImageColor;
  135. mDisabledImageColor = LLUI::sButtonImageColor;
  136. if (!unselected_image_name.empty())
  137. {
  138. // User-specified image; do not use fixed borders unless requested
  139. setImageUnselected(unselected_image_name);
  140. setImageDisabled(unselected_image_name);
  141. mDisabledImageColor.mV[VALPHA] = 0.5f;
  142. mScaleImage = false;
  143. }
  144. else
  145. {
  146. setImageUnselected("button_enabled_32x128.tga");
  147. setImageDisabled("button_disabled_32x128.tga");
  148. }
  149. if (!selected_image_name.empty())
  150. {
  151. // User-specified image; do not use fixed borders unless requested
  152. setImageSelected(selected_image_name);
  153. setImageDisabledSelected(selected_image_name);
  154. mDisabledImageColor.mV[VALPHA] = 0.5f;
  155. mScaleImage = false;
  156. }
  157. else
  158. {
  159. setImageSelected("button_enabled_selected_32x128.tga");
  160. setImageDisabledSelected("button_disabled_32x128.tga");
  161. }
  162. init(click_callback, callback_data, font, control_name);
  163. }
  164. void LLButton::init(void (*click_callback)(void*), void* callback_data,
  165. const LLFontGL* font, const char* control_name)
  166. {
  167. mGLFont = font ? font : LLFontGL::getFontSansSerif();
  168. // *HACK: to make sure there is space for at least one character
  169. if (getRect().getWidth() - mRightHPad - mLeftHPad < mGLFont->getWidth(" "))
  170. {
  171. // Use old defaults
  172. mLeftHPad = LLBUTTON_ORIG_H_PAD;
  173. mRightHPad = LLBUTTON_ORIG_H_PAD;
  174. }
  175. mCallbackUserData = callback_data;
  176. mMouseDownTimer.stop();
  177. setControlName(control_name, NULL);
  178. mUnselectedLabelColor = LLUI::sButtonLabelColor;
  179. mSelectedLabelColor = LLUI::sButtonLabelSelectedColor;
  180. mDisabledLabelColor = LLUI::sButtonLabelDisabledColor;
  181. mDisabledSelectedLabelColor = LLUI::sButtonLabelSelectedDisabledColor;
  182. mFlashBgColor = LLUI::sButtonFlashBgColor;
  183. mImageOverlayAlignment = LLFontGL::HCENTER;
  184. mImageOverlayColor = LLColor4::white;
  185. }
  186. LLButton::~LLButton()
  187. {
  188. if (hasMouseCapture())
  189. {
  190. gFocusMgr.setMouseCapture(NULL);
  191. }
  192. }
  193. // *HACK: committing a button is the same as instantly clicking it.
  194. //virtual
  195. void LLButton::onCommit()
  196. {
  197. // WARNING: Sometimes clicking a button destroys the floater or panel
  198. // containing it. Therefore we need to call mClickedCallback LAST,
  199. // otherwise this becomes deleted memory.
  200. LLUICtrl::onCommit();
  201. if (mMouseDownCallback)
  202. {
  203. (*mMouseDownCallback)(mCallbackUserData);
  204. }
  205. if (mMouseUpCallback)
  206. {
  207. (*mMouseUpCallback)(mCallbackUserData);
  208. }
  209. if (getSoundFlags() & MOUSE_DOWN)
  210. {
  211. make_ui_sound("UISndClick");
  212. }
  213. if (getSoundFlags() & MOUSE_UP)
  214. {
  215. make_ui_sound("UISndClickRelease");
  216. }
  217. if (mIsToggle)
  218. {
  219. toggleState();
  220. }
  221. // Do this last, as it can result in destroying this button
  222. if (mCommitCallback)
  223. {
  224. (*mCommitCallback)(this, mCallbackUserData);
  225. }
  226. else if (mClickedCallback)
  227. {
  228. (*mClickedCallback)(mCallbackUserData);
  229. }
  230. }
  231. bool LLButton::handleUnicodeCharHere(llwchar uni_char)
  232. {
  233. bool handled = false;
  234. if (uni_char == ' ' && gKeyboardp && !gKeyboardp->getKeyRepeated(' '))
  235. {
  236. if (mIsToggle)
  237. {
  238. toggleState();
  239. }
  240. handled = true;
  241. if (mCommitCallback)
  242. {
  243. (*mCommitCallback)(this, mCallbackUserData);
  244. }
  245. else if (mClickedCallback)
  246. {
  247. (*mClickedCallback)(mCallbackUserData);
  248. }
  249. }
  250. return handled;
  251. }
  252. bool LLButton::handleKeyHere(KEY key, MASK mask)
  253. {
  254. bool handled = false;
  255. if (mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE &&
  256. gKeyboardp && !gKeyboardp->getKeyRepeated(key))
  257. {
  258. if (mIsToggle)
  259. {
  260. toggleState();
  261. }
  262. handled = true;
  263. if (mCommitCallback)
  264. {
  265. (*mCommitCallback)(this, mCallbackUserData);
  266. }
  267. else if (mClickedCallback)
  268. {
  269. (*mClickedCallback)(mCallbackUserData);
  270. }
  271. }
  272. return handled;
  273. }
  274. bool LLButton::handleMouseDown(S32, S32, MASK)
  275. {
  276. // Route future Mouse messages here preemptively (release on mouse up).
  277. gFocusMgr.setMouseCapture(this);
  278. if (hasTabStop() && !getIsChrome())
  279. {
  280. setFocus(true);
  281. }
  282. if (mMouseDownCallback)
  283. {
  284. (*mMouseDownCallback)(mCallbackUserData);
  285. }
  286. mMouseDownTimer.start();
  287. mMouseDownFrame = (S32)LLFrameTimer::getFrameCount();
  288. if (getSoundFlags() & MOUSE_DOWN)
  289. {
  290. make_ui_sound("UISndClick");
  291. }
  292. return true;
  293. }
  294. bool LLButton::handleMouseUp(S32 x, S32 y, MASK)
  295. {
  296. // We only handle the click if the click both started and ended within us
  297. if (hasMouseCapture())
  298. {
  299. // Always release the mouse
  300. gFocusMgr.setMouseCapture(NULL);
  301. // Regardless of where mouseup occurs, handle callback
  302. if (mMouseUpCallback)
  303. {
  304. (*mMouseUpCallback)(mCallbackUserData);
  305. }
  306. mMouseDownTimer.stop();
  307. mMouseDownTimer.reset();
  308. // DO THIS AT THE VERY END to allow the button to be destroyed as a
  309. // result of being clicked.
  310. // If mouse-up in the widget, it has been clicked
  311. if (pointInView(x, y))
  312. {
  313. if (getSoundFlags() & MOUSE_UP)
  314. {
  315. make_ui_sound("UISndClickRelease");
  316. }
  317. if (mIsToggle)
  318. {
  319. toggleState();
  320. }
  321. if (mCommitCallback)
  322. {
  323. (*mCommitCallback)(this, mCallbackUserData);
  324. }
  325. else if (mClickedCallback)
  326. {
  327. (*mClickedCallback)(mCallbackUserData);
  328. }
  329. }
  330. }
  331. return true;
  332. }
  333. bool LLButton::handleHover(S32, S32, MASK)
  334. {
  335. LLMouseHandler* other_captor = gFocusMgr.getMouseCapture();
  336. mNeedsHighlight = other_captor == NULL || other_captor == this ||
  337. // This following bit is to support modal dialogs
  338. (other_captor->isView() &&
  339. hasAncestor((LLView*)other_captor));
  340. if (mMouseHoverCallback)
  341. {
  342. (*mMouseHoverCallback)(mCallbackUserData);
  343. }
  344. if (mMouseDownTimer.getStarted() && mHeldDownCallback)
  345. {
  346. F32 elapsed = getHeldDownTime();
  347. if (mHeldDownDelay <= elapsed && mHeldDownFrameDelay <=
  348. (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame)
  349. {
  350. mHeldDownCallback(mCallbackUserData);
  351. }
  352. }
  353. // We only handle the click if the click both started and ended within us
  354. gWindowp->setCursor(UI_CURSOR_ARROW);
  355. LL_DEBUGS("UserInput") << "Hover handled by " << getName() << LL_ENDL;
  356. return true;
  357. }
  358. //virtual
  359. void LLButton::draw()
  360. {
  361. bool flash = false;
  362. if (mFlashing)
  363. {
  364. F32 elapsed = mFlashingTimer.getElapsedTimeF32();
  365. S32 flash_count = S32(elapsed * LLUI::sButtonFlashRate * 2.f);
  366. // Flash on or off ?
  367. flash = flash_count % 2 == 0 ||
  368. flash_count > 2 * LLUI::sButtonFlashCount;
  369. }
  370. bool pressed_by_keyboard = false;
  371. if (hasFocus() && gKeyboardp)
  372. {
  373. pressed_by_keyboard = gKeyboardp->getKeyDown(' ') ||
  374. (mCommitOnReturn &&
  375. gKeyboardp->getKeyDown(KEY_RETURN));
  376. }
  377. // Unselected image assignments
  378. S32 local_mouse_x;
  379. S32 local_mouse_y;
  380. LLUI::getCursorPositionLocal(this, &local_mouse_x, &local_mouse_y);
  381. bool pressed = pressed_by_keyboard || mToggleState ||
  382. (hasMouseCapture() &&
  383. pointInView(local_mouse_x, local_mouse_y));
  384. bool use_glow_effect = false;
  385. LLColor4 glow_color = LLColor4::white;
  386. U32 glow_type = LLRender::BT_ADD_WITH_ALPHA;
  387. if (mNeedsHighlight)
  388. {
  389. if (pressed)
  390. {
  391. if (mImageHoverSelected)
  392. {
  393. mImagep = mImageHoverSelected;
  394. }
  395. else
  396. {
  397. mImagep = mImageSelected;
  398. use_glow_effect = true;
  399. }
  400. }
  401. else if (mImageHoverUnselected)
  402. {
  403. mImagep = mImageHoverUnselected;
  404. }
  405. else
  406. {
  407. mImagep = mImageUnselected;
  408. use_glow_effect = true;
  409. }
  410. }
  411. else if (pressed)
  412. {
  413. mImagep = mImageSelected;
  414. }
  415. else
  416. {
  417. mImagep = mImageUnselected;
  418. }
  419. if (mFlashing)
  420. {
  421. use_glow_effect = true;
  422. glow_type = LLRender::BT_ALPHA; // blend the glow
  423. if (mNeedsHighlight) // highlighted AND flashing
  424. {
  425. // Average between flash and highlight colour, with sum of the
  426. // opacity
  427. glow_color = (glow_color * 0.5f + mFlashBgColor * 0.5f) % 2.f;
  428. }
  429. else
  430. {
  431. glow_color = mFlashBgColor;
  432. }
  433. }
  434. // Override if more data is available
  435. // *HACK: Use gray checked state to mean either:
  436. // enabled and tentative
  437. // or
  438. // disabled but checked
  439. bool enabled = getEnabled();
  440. if (!mImageDisabledSelected.isNull() &&
  441. ((enabled && getTentative()) || (!enabled && pressed)))
  442. {
  443. mImagep = mImageDisabledSelected;
  444. }
  445. else if (!mImageDisabled.isNull() && !enabled && !pressed)
  446. {
  447. mImagep = mImageDisabled;
  448. }
  449. if (mNeedsHighlight && !mImagep)
  450. {
  451. use_glow_effect = true;
  452. }
  453. // Figure out appropriate color for the text
  454. LLColor4 label_color;
  455. // Label changes when button state changes, not when pressed
  456. if (enabled)
  457. {
  458. if (mToggleState)
  459. {
  460. label_color = mSelectedLabelColor;
  461. }
  462. else
  463. {
  464. label_color = mUnselectedLabelColor;
  465. }
  466. }
  467. else if (mToggleState)
  468. {
  469. label_color = mDisabledSelectedLabelColor;
  470. }
  471. else
  472. {
  473. label_color = mDisabledLabelColor;
  474. }
  475. // Unselected label assignments
  476. LLWString label;
  477. if (mToggleState)
  478. {
  479. if (enabled || mDisabledSelectedLabel.empty())
  480. {
  481. label = mSelectedLabel;
  482. }
  483. else
  484. {
  485. label = mDisabledSelectedLabel;
  486. }
  487. }
  488. else if (enabled || mDisabledLabel.empty())
  489. {
  490. label = mUnselectedLabel;
  491. }
  492. else
  493. {
  494. label = mDisabledLabel;
  495. }
  496. // Overlay with keyboard focus border
  497. if (hasFocus())
  498. {
  499. F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
  500. drawBorder(gFocusMgr.getFocusColor(),
  501. ll_roundp(lerp(1.f, 3.f, lerp_amt)));
  502. }
  503. if (use_glow_effect)
  504. {
  505. mCurGlowStrength = lerp(mCurGlowStrength,
  506. mFlashing ? (flash ? 1.f : 0.f)
  507. : mHoverGlowStrength,
  508. LLCriticalDamp::getInterpolant(0.05f));
  509. }
  510. else
  511. {
  512. mCurGlowStrength = lerp(mCurGlowStrength, 0.f,
  513. LLCriticalDamp::getInterpolant(0.05f));
  514. }
  515. // Draw button image, if available. Otherwise draw basic rectangular
  516. // button.
  517. if (mImagep.notNull())
  518. {
  519. if (mScaleImage)
  520. {
  521. mImagep->draw(getLocalRect(),
  522. enabled ? mImageColor : mDisabledImageColor);
  523. if (mCurGlowStrength > 0.01f)
  524. {
  525. gGL.setSceneBlendType(glow_type);
  526. mImagep->drawSolid(0, 0, getRect().getWidth(),
  527. getRect().getHeight(),
  528. glow_color % mCurGlowStrength);
  529. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  530. }
  531. }
  532. else
  533. {
  534. mImagep->draw(0, 0,
  535. enabled ? mImageColor : mDisabledImageColor);
  536. if (mCurGlowStrength > 0.01f)
  537. {
  538. gGL.setSceneBlendType(glow_type);
  539. mImagep->drawSolid(0, 0, glow_color % mCurGlowStrength);
  540. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  541. }
  542. }
  543. }
  544. else
  545. {
  546. // No image
  547. llwarns << "No image for button " << getName() << llendl;
  548. // Draw it in pink so we can find it
  549. gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0,
  550. LLColor4::pink1, false);
  551. }
  552. // Let overlay image and text play well together
  553. S32 text_left = mLeftHPad;
  554. S32 text_right = getRect().getWidth() - mRightHPad;
  555. S32 text_width = getRect().getWidth() - mLeftHPad - mRightHPad;
  556. // Draw overlay image
  557. if (mImageOverlay.notNull())
  558. {
  559. // Get max width and height (discard level 0)
  560. S32 overlay_width = mImageOverlay->getWidth();
  561. S32 overlay_height = mImageOverlay->getHeight();
  562. F32 scale_factor = llmin((F32)getRect().getWidth() /
  563. (F32)overlay_width,
  564. (F32)getRect().getHeight() /
  565. (F32)overlay_height, 1.f);
  566. overlay_width = ll_roundp((F32)overlay_width * scale_factor);
  567. overlay_height = ll_roundp((F32)overlay_height * scale_factor);
  568. S32 center_x = getLocalRect().getCenterX();
  569. S32 center_y = getLocalRect().getCenterY();
  570. // *HACK: for "depressed" buttons
  571. if (pressed)
  572. {
  573. --center_y;
  574. ++center_x;
  575. }
  576. // Fade out overlay images on disabled buttons
  577. LLColor4 overlay_color = mImageOverlayColor;
  578. if (!enabled)
  579. {
  580. overlay_color.mV[VALPHA] = 0.5f;
  581. }
  582. switch (mImageOverlayAlignment)
  583. {
  584. case LLFontGL::LEFT:
  585. text_left += overlay_width + 1;
  586. text_width -= overlay_width + 1;
  587. mImageOverlay->draw(mLeftHPad, center_y - overlay_height / 2,
  588. overlay_width, overlay_height,
  589. overlay_color);
  590. break;
  591. case LLFontGL::HCENTER:
  592. mImageOverlay->draw(center_x - overlay_width / 2,
  593. center_y - overlay_height / 2,
  594. overlay_width, overlay_height,
  595. overlay_color);
  596. break;
  597. case LLFontGL::RIGHT:
  598. text_right -= overlay_width + 1;
  599. text_width -= overlay_width + 1;
  600. mImageOverlay->draw(getRect().getWidth() - mRightHPad -
  601. overlay_width,
  602. center_y - overlay_height / 2,
  603. overlay_width, overlay_height,
  604. overlay_color);
  605. break;
  606. default:
  607. // Draw nothing
  608. break;
  609. }
  610. }
  611. // Draw label
  612. if (!label.empty())
  613. {
  614. LLWStringUtil::trim(label);
  615. S32 x;
  616. switch (mHAlign)
  617. {
  618. case LLFontGL::RIGHT:
  619. x = text_right;
  620. break;
  621. case LLFontGL::HCENTER:
  622. x = getRect().getWidth() / 2;
  623. break;
  624. case LLFontGL::LEFT:
  625. default:
  626. x = text_left;
  627. }
  628. S32 y_offset = 2 + (getRect().getHeight() - 20) / 2;
  629. if (pressed)
  630. {
  631. --y_offset;
  632. ++x;
  633. }
  634. mGLFont->render(label, 0, (F32)x, (F32)(gButtonVPad + y_offset),
  635. label_color, mHAlign, LLFontGL::BOTTOM,
  636. mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT
  637. : LLFontGL::NORMAL,
  638. U32_MAX, text_width, NULL, false, false);
  639. }
  640. if (sDebugRects || (LLView::sEditingUI && LLView::sEditingUIView == this))
  641. {
  642. drawDebugRect();
  643. }
  644. // Reset hover status for next frame
  645. mNeedsHighlight = false;
  646. }
  647. void LLButton::drawBorder(const LLColor4& color, S32 size)
  648. {
  649. if (mScaleImage)
  650. {
  651. mImagep->drawBorder(getLocalRect(), color, size);
  652. }
  653. else
  654. {
  655. mImagep->drawBorder(0, 0, color, size);
  656. }
  657. }
  658. void LLButton::setClickedCallback(void (*cb)(void*), void* userdata)
  659. {
  660. mClickedCallback = cb;
  661. if (userdata)
  662. {
  663. mCallbackUserData = userdata;
  664. }
  665. }
  666. void LLButton::setToggleState(bool b)
  667. {
  668. if (b != mToggleState)
  669. {
  670. setControlValue(b); // Will fire LLControlVariable callbacks (if any)
  671. mToggleState = b; // May or may not be redundant
  672. }
  673. }
  674. void LLButton::setFlashing(bool b)
  675. {
  676. if (b != mFlashing)
  677. {
  678. mFlashing = b;
  679. mFlashingTimer.reset();
  680. }
  681. }
  682. bool LLButton::toggleState()
  683. {
  684. setToggleState(!mToggleState);
  685. return mToggleState;
  686. }
  687. void LLButton::setImageUnselected(LLUIImagePtr image)
  688. {
  689. mImageUnselected = image;
  690. }
  691. void LLButton::setImages(const std::string& image_name,
  692. const std::string& selected_name)
  693. {
  694. setImageUnselected(image_name);
  695. setImageSelected(selected_name);
  696. }
  697. void LLButton::setImages(const std::string& image_name)
  698. {
  699. setImageUnselected(image_name);
  700. setImageSelected(image_name);
  701. }
  702. void LLButton::setImageSelected(LLUIImagePtr image)
  703. {
  704. mImageSelected = image;
  705. }
  706. void LLButton::setImageColor(const LLColor4& c)
  707. {
  708. mImageColor = c;
  709. }
  710. void LLButton::setColor(const LLColor4& color)
  711. {
  712. setImageColor(color);
  713. }
  714. void LLButton::setAlpha(F32 alpha)
  715. {
  716. mImageColor.setAlpha(alpha);
  717. mDisabledImageColor.setAlpha(alpha * 0.5f);
  718. }
  719. void LLButton::setImageDisabled(LLUIImagePtr image)
  720. {
  721. mImageDisabled = image;
  722. mDisabledImageColor = mImageColor;
  723. mDisabledImageColor.mV[VALPHA] *= 0.5f;
  724. }
  725. void LLButton::setImageDisabledSelected(LLUIImagePtr image)
  726. {
  727. mImageDisabledSelected = image;
  728. mDisabledImageColor = mImageColor;
  729. mDisabledImageColor.mV[VALPHA] *= 0.5f;
  730. }
  731. void LLButton::setDisabledImages(const std::string& image_name,
  732. const std::string& selected_name,
  733. const LLColor4& c)
  734. {
  735. setImageDisabled(image_name);
  736. setImageDisabledSelected(selected_name);
  737. mDisabledImageColor = c;
  738. }
  739. void LLButton::setImageHoverSelected(LLUIImagePtr image)
  740. {
  741. mImageHoverSelected = image;
  742. }
  743. void LLButton::setDisabledImages(const std::string& image_name,
  744. const std::string& selected_name)
  745. {
  746. LLColor4 clr = mImageColor;
  747. clr.mV[VALPHA] *= .5f;
  748. setDisabledImages(image_name, selected_name, clr);
  749. }
  750. void LLButton::setImageHoverUnselected(LLUIImagePtr image)
  751. {
  752. mImageHoverUnselected = image;
  753. }
  754. void LLButton::setHoverImages(const std::string& image_name,
  755. const std::string& selected_name)
  756. {
  757. setImageHoverUnselected(image_name);
  758. setImageHoverSelected(selected_name);
  759. }
  760. void LLButton::setImageOverlay(const std::string& image_name,
  761. LLFontGL::HAlign alignment,
  762. const LLColor4& color)
  763. {
  764. if (image_name.empty())
  765. {
  766. mImageOverlay = NULL;
  767. }
  768. else
  769. {
  770. mImageOverlay = LLUI::getUIImage(image_name);
  771. mImageOverlayAlignment = alignment;
  772. mImageOverlayColor = color;
  773. }
  774. }
  775. void LLButton::setImageOverlay(LLUIImagePtr image,
  776. LLFontGL::HAlign alignment,
  777. const LLColor4& color)
  778. {
  779. mImageOverlay = image;
  780. mImageOverlayAlignment = alignment;
  781. mImageOverlayColor = color;
  782. }
  783. void LLButton::onMouseCaptureLost()
  784. {
  785. mMouseDownTimer.stop();
  786. mMouseDownTimer.reset();
  787. }
  788. void LLButton::setImageUnselected(const std::string& image_name)
  789. {
  790. setImageUnselected(LLUI::getUIImage(image_name));
  791. mImageUnselectedName = image_name;
  792. }
  793. void LLButton::setImageSelected(const std::string& image_name)
  794. {
  795. setImageSelected(LLUI::getUIImage(image_name));
  796. mImageSelectedName = image_name;
  797. }
  798. void LLButton::setImageHoverSelected(const std::string& image_name)
  799. {
  800. setImageHoverSelected(LLUI::getUIImage(image_name));
  801. mImageHoverSelectedName = image_name;
  802. }
  803. void LLButton::setImageHoverUnselected(const std::string& image_name)
  804. {
  805. setImageHoverUnselected(LLUI::getUIImage(image_name));
  806. mImageHoverUnselectedName = image_name;
  807. }
  808. void LLButton::setImageDisabled(const std::string& image_name)
  809. {
  810. setImageDisabled(LLUI::getUIImage(image_name));
  811. mImageDisabledName = image_name;
  812. }
  813. void LLButton::setImageDisabledSelected(const std::string& image_name)
  814. {
  815. setImageDisabledSelected(LLUI::getUIImage(image_name));
  816. mImageDisabledSelectedName = image_name;
  817. }
  818. void LLButton::addImageAttributeToXML(LLXMLNodePtr node,
  819. const std::string& image_name,
  820. const LLUUID& image_id,
  821. const std::string& xml_tag_name) const
  822. {
  823. if (!image_name.empty())
  824. {
  825. node->createChild(xml_tag_name.c_str(),
  826. true)->setStringValue(image_name);
  827. }
  828. else if (image_id.notNull())
  829. {
  830. node->createChild((xml_tag_name + "_id").c_str(),
  831. true)->setUUIDValue(image_id);
  832. }
  833. }
  834. //virtual
  835. const std::string& LLButton::getTag() const
  836. {
  837. return LL_BUTTON_TAG;
  838. }
  839. //virtual
  840. LLXMLNodePtr LLButton::getXML(bool save_children) const
  841. {
  842. LLXMLNodePtr node = LLUICtrl::getXML();
  843. node->setName(LL_BUTTON_TAG);
  844. node->createChild("label", true)->setStringValue(getLabelUnselected());
  845. node->createChild("label_selected",
  846. true)->setStringValue(getLabelSelected());
  847. node->createChild("font",
  848. true)->setStringValue(LLFontGL::nameFromFont(mGLFont));
  849. node->createChild("halign",
  850. true)->setStringValue(LLFontGL::nameFromHAlign(mHAlign));
  851. addImageAttributeToXML(node, mImageUnselectedName, mImageUnselectedID,
  852. "image_unselected");
  853. addImageAttributeToXML(node, mImageSelectedName, mImageSelectedID,
  854. "image_selected");
  855. addImageAttributeToXML(node, mImageHoverSelectedName,
  856. mImageHoverSelectedID, "image_hover_selected");
  857. addImageAttributeToXML(node, mImageHoverUnselectedName,
  858. mImageHoverUnselectedID, "image_hover_unselected");
  859. addImageAttributeToXML(node, mImageDisabledName, mImageDisabledID,
  860. "image_disabled");
  861. addImageAttributeToXML(node, mImageDisabledSelectedName,
  862. mImageDisabledSelectedID,
  863. "image_disabled_selected");
  864. node->createChild("scale_image", true)->setBoolValue(mScaleImage);
  865. return node;
  866. }
  867. void clicked_help(void* data)
  868. {
  869. LLButton* self = (LLButton*)data;
  870. if (self && LLUI::sHtmlHelp)
  871. {
  872. LLUI::sHtmlHelp->show(self->getHelpURL());
  873. }
  874. }
  875. //static
  876. LLView* LLButton::fromXML(LLXMLNodePtr node, LLView* parent,
  877. LLUICtrlFactory* factory)
  878. {
  879. std::string name = LL_BUTTON_TAG;
  880. node->getAttributeString("name", name);
  881. std::string label = name;
  882. node->getAttributeString("label", label);
  883. std::string label_selected = label;
  884. node->getAttributeString("label_selected", label_selected);
  885. LLFontGL* font = selectFont(node);
  886. std::string image_unselected;
  887. if (node->hasAttribute("image_unselected"))
  888. {
  889. node->getAttributeString("image_unselected", image_unselected);
  890. }
  891. std::string image_selected;
  892. if (node->hasAttribute("image_selected"))
  893. {
  894. node->getAttributeString("image_selected", image_selected);
  895. }
  896. std::string image_hover_selected;
  897. if (node->hasAttribute("image_hover_selected"))
  898. {
  899. node->getAttributeString("image_hover_selected", image_hover_selected);
  900. }
  901. std::string image_hover_unselected;
  902. if (node->hasAttribute("image_hover_unselected"))
  903. {
  904. node->getAttributeString("image_hover_unselected",
  905. image_hover_unselected);
  906. }
  907. std::string image_disabled_selected;
  908. if (node->hasAttribute("image_disabled_selected"))
  909. {
  910. node->getAttributeString("image_disabled_selected",
  911. image_disabled_selected);
  912. }
  913. std::string image_disabled;
  914. if (node->hasAttribute("image_disabled"))
  915. {
  916. node->getAttributeString("image_disabled", image_disabled);
  917. }
  918. std::string image_overlay;
  919. node->getAttributeString("image_overlay", image_overlay);
  920. LLFontGL::HAlign image_overlay_alignment = LLFontGL::HCENTER;
  921. std::string overlay_align_str;
  922. if (node->hasAttribute("image_overlay_alignment"))
  923. {
  924. node->getAttributeString("image_overlay_alignment",
  925. overlay_align_str);
  926. image_overlay_alignment = LLFontGL::hAlignFromName(overlay_align_str);
  927. }
  928. LLButton* button = new LLButton(name, LLRect(), image_unselected,
  929. image_selected, NULL, NULL,
  930. parent, font, label, label_selected);
  931. node->getAttributeS32("pad_right", button->mRightHPad);
  932. node->getAttributeS32("pad_left", button->mLeftHPad);
  933. bool is_toggle = button->getIsToggle();
  934. node->getAttributeBool("toggle", is_toggle);
  935. button->setIsToggle(is_toggle);
  936. if (image_hover_selected != LLStringUtil::null)
  937. {
  938. button->setImageHoverSelected(image_hover_selected);
  939. }
  940. if (image_hover_unselected != LLStringUtil::null)
  941. {
  942. button->setImageHoverUnselected(image_hover_unselected);
  943. }
  944. if (image_disabled_selected != LLStringUtil::null)
  945. {
  946. button->setImageDisabledSelected(image_disabled_selected);
  947. }
  948. if (image_disabled != LLStringUtil::null)
  949. {
  950. button->setImageDisabled(image_disabled);
  951. }
  952. if (image_overlay != LLStringUtil::null)
  953. {
  954. button->setImageOverlay(image_overlay, image_overlay_alignment);
  955. }
  956. if (node->hasAttribute("halign"))
  957. {
  958. LLFontGL::HAlign halign = selectFontHAlign(node);
  959. button->setHAlign(halign);
  960. }
  961. if (node->hasAttribute("scale_image"))
  962. {
  963. bool needs_scale = false;
  964. node->getAttributeBool("scale_image", needs_scale);
  965. button->setScaleImage(needs_scale);
  966. }
  967. if (label.empty())
  968. {
  969. button->setLabelUnselected(node->getTextContents());
  970. }
  971. if (label_selected.empty())
  972. {
  973. button->setLabelSelected(node->getTextContents());
  974. }
  975. if (node->hasAttribute("help_url"))
  976. {
  977. std::string help_url;
  978. node->getAttributeString("help_url", help_url);
  979. button->setHelpURLCallback(help_url);
  980. }
  981. button->initFromXML(node, parent);
  982. return button;
  983. }
  984. void LLButton::setHelpURLCallback(const std::string& help_url)
  985. {
  986. mHelpURL = help_url;
  987. setClickedCallback(clicked_help, this);
  988. }