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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llbutton.cpp
  3.  * @brief LLButton 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. #define LLBUTTON_CPP
  34. #include "llbutton.h"
  35. // Linden library includes
  36. #include "v4color.h"
  37. #include "llstring.h"
  38. // Project includes
  39. #include "llkeyboard.h"
  40. #include "llui.h"
  41. #include "lluiconstants.h"
  42. #include "llresmgr.h"
  43. #include "llcriticaldamp.h"
  44. #include "llfloater.h"
  45. #include "llfloaterreg.h"
  46. #include "llfocusmgr.h"
  47. #include "llwindow.h"
  48. #include "llnotificationsutil.h"
  49. #include "llrender.h"
  50. #include "lluictrlfactory.h"
  51. #include "llhelp.h"
  52. #include "lldockablefloater.h"
  53. static LLDefaultChildRegistry::Register<LLButton> r("button");
  54. // Compiler optimization, generate extern template
  55. template class LLButton* LLView::getChild<class LLButton>(
  56. const std::string& name, BOOL recurse) const;
  57. // globals loaded from settings.xml
  58. S32 LLBUTTON_H_PAD = 0;
  59. S32 BTN_HEIGHT_SMALL= 0;
  60. S32 BTN_HEIGHT = 0;
  61. LLButton::Params::Params()
  62. : label_selected("label_selected"), // requires is_toggle true
  63. label_shadow("label_shadow", true),
  64. auto_resize("auto_resize", false),
  65. use_ellipses("use_ellipses", false),
  66. image_unselected("image_unselected"),
  67. image_selected("image_selected"),
  68. image_hover_selected("image_hover_selected"),
  69. image_hover_unselected("image_hover_unselected"),
  70. image_disabled_selected("image_disabled_selected"),
  71. image_disabled("image_disabled"),
  72. image_pressed("image_pressed"),
  73. image_pressed_selected("image_pressed_selected"),
  74. image_overlay("image_overlay"),
  75. image_overlay_alignment("image_overlay_alignment", std::string("center")),
  76. image_top_pad("image_top_pad"),
  77. image_bottom_pad("image_bottom_pad"),
  78. imgoverlay_label_space("imgoverlay_label_space", 1),
  79. label_color("label_color"),
  80. label_color_selected("label_color_selected"), // requires is_toggle true
  81. label_color_disabled("label_color_disabled"),
  82. label_color_disabled_selected("label_color_disabled_selected"),
  83. highlight_color("highlight_color"),
  84. image_color("image_color"),
  85. image_color_disabled("image_color_disabled"),
  86. image_overlay_color("image_overlay_color", LLColor4::white),
  87. flash_color("flash_color"),
  88. pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),
  89. pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),
  90. pad_bottom("pad_bottom"),
  91. click_callback("click_callback"),
  92. mouse_down_callback("mouse_down_callback"),
  93. mouse_up_callback("mouse_up_callback"),
  94. mouse_held_callback("mouse_held_callback"),
  95. is_toggle("is_toggle", false),
  96. scale_image("scale_image", true),
  97. hover_glow_amount("hover_glow_amount"),
  98. commit_on_return("commit_on_return", true)
  99. {
  100. addSynonym(is_toggle, "toggle");
  101. held_down_delay.seconds = 0.5f;
  102. initial_value.set(LLSD(false), false);
  103. }
  104. LLButton::LLButton(const LLButton::Params& p)
  105. : LLUICtrl(p),
  106. mMouseDownFrame(0),
  107. mMouseHeldDownCount(0),
  108. mBorderEnabled( FALSE ),
  109. mFlashing( FALSE ),
  110. mCurGlowStrength(0.f),
  111. mNeedsHighlight(FALSE),
  112. mUnselectedLabel(p.label()),
  113. mSelectedLabel(p.label_selected()),
  114. mGLFont(p.font),
  115. mHeldDownDelay(p.held_down_delay.seconds), // seconds until held-down callback is called
  116. mHeldDownFrameDelay(p.held_down_delay.frames),
  117. mImageUnselected(p.image_unselected),
  118. mImageSelected(p.image_selected),
  119. mImageDisabled(p.image_disabled),
  120. mImageDisabledSelected(p.image_disabled_selected),
  121. mImagePressed(p.image_pressed),
  122. mImagePressedSelected(p.image_pressed_selected),
  123. mImageHoverSelected(p.image_hover_selected),
  124. mImageHoverUnselected(p.image_hover_unselected),
  125. mUnselectedLabelColor(p.label_color()),
  126. mSelectedLabelColor(p.label_color_selected()),
  127. mDisabledLabelColor(p.label_color_disabled()),
  128. mDisabledSelectedLabelColor(p.label_color_disabled_selected()),
  129. mHighlightColor(p.highlight_color()),
  130. mImageColor(p.image_color()),
  131. mFlashBgColor(p.flash_color()),
  132. mDisabledImageColor(p.image_color_disabled()),
  133. mImageOverlay(p.image_overlay()),
  134. mImageOverlayColor(p.image_overlay_color()),
  135. mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)),
  136. mImageOverlayTopPad(p.image_top_pad),
  137. mImageOverlayBottomPad(p.image_bottom_pad),
  138. mImgOverlayLabelSpace(p.imgoverlay_label_space),
  139. mIsToggle(p.is_toggle),
  140. mScaleImage(p.scale_image),
  141. mDropShadowedText(p.label_shadow),
  142. mAutoResize(p.auto_resize),
  143. mUseEllipses( p.use_ellipses ),
  144. mHAlign(p.font_halign),
  145. mLeftHPad(p.pad_left),
  146. mRightHPad(p.pad_right),
  147. mBottomVPad(p.pad_bottom),
  148. mHoverGlowStrength(p.hover_glow_amount),
  149. mCommitOnReturn(p.commit_on_return),
  150. mFadeWhenDisabled(FALSE),
  151. mForcePressedState(false),
  152. mLastDrawCharsCount(0),
  153. mMouseDownSignal(NULL),
  154. mMouseUpSignal(NULL),
  155. mHeldDownSignal(NULL)
  156. {
  157. static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
  158. static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>());
  159. if (!p.label_selected.isProvided())
  160. {
  161. mSelectedLabel = mUnselectedLabel;
  162. }
  163. // Hack to make sure there is space for at least one character
  164. if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
  165. {
  166. // Use old defaults
  167. mLeftHPad = llbutton_orig_h_pad;
  168. mRightHPad = llbutton_orig_h_pad;
  169. }
  170. mMouseDownTimer.stop();
  171. // if custom unselected button image provided...
  172. if (p.image_unselected != default_params.image_unselected)
  173. {
  174. //...fade it out for disabled image by default...
  175. if (p.image_disabled() == default_params.image_disabled() )
  176. {
  177. mImageDisabled = p.image_unselected;
  178. mFadeWhenDisabled = TRUE;
  179. }
  180. if (p.image_pressed_selected == default_params.image_pressed_selected)
  181. {
  182. mImagePressedSelected = mImageUnselected;
  183. }
  184. }
  185. // if custom selected button image provided...
  186. if (p.image_selected != default_params.image_selected)
  187. {
  188. //...fade it out for disabled image by default...
  189. if (p.image_disabled_selected() == default_params.image_disabled_selected())
  190. {
  191. mImageDisabledSelected = p.image_selected;
  192. mFadeWhenDisabled = TRUE;
  193. }
  194. if (p.image_pressed == default_params.image_pressed)
  195. {
  196. mImagePressed = mImageSelected;
  197. }
  198. }
  199. if (!p.image_pressed.isProvided())
  200. {
  201. mImagePressed = mImageSelected;
  202. }
  203. if (!p.image_pressed_selected.isProvided())
  204. {
  205. mImagePressedSelected = mImageUnselected;
  206. }
  207. if (mImageUnselected.isNull())
  208. {
  209. llwarns << "Button: " << getName() << " with no image!" << llendl;
  210. }
  211. if (p.click_callback.isProvided())
  212. {
  213. setCommitCallback(initCommitCallback(p.click_callback)); // alias -> commit_callback
  214. }
  215. if (p.mouse_down_callback.isProvided())
  216. {
  217. setMouseDownCallback(initCommitCallback(p.mouse_down_callback));
  218. }
  219. if (p.mouse_up_callback.isProvided())
  220. {
  221. setMouseUpCallback(initCommitCallback(p.mouse_up_callback));
  222. }
  223. if (p.mouse_held_callback.isProvided())
  224. {
  225. setHeldDownCallback(initCommitCallback(p.mouse_held_callback));
  226. }
  227. }
  228. LLButton::~LLButton()
  229. {
  230. delete mMouseDownSignal;
  231. delete mMouseUpSignal;
  232. delete mHeldDownSignal;
  233. }
  234. // HACK: Committing a button is the same as instantly clicking it.
  235. // virtual
  236. void LLButton::onCommit()
  237. {
  238. // WARNING: Sometimes clicking a button destroys the floater or
  239. // panel containing it.  Therefore we need to call  LLUICtrl::onCommit()
  240. // LAST, otherwise this becomes deleted memory.
  241. if (mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
  242. if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
  243. if (getSoundFlags() & MOUSE_DOWN)
  244. {
  245. make_ui_sound("UISndClick");
  246. }
  247. if (getSoundFlags() & MOUSE_UP)
  248. {
  249. make_ui_sound("UISndClickRelease");
  250. }
  251. if (mIsToggle)
  252. {
  253. toggleState();
  254. }
  255. // do this last, as it can result in destroying this button
  256. LLUICtrl::onCommit();
  257. }
  258. boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )
  259. {
  260. if (!mCommitSignal) mCommitSignal = new commit_signal_t();
  261. return mCommitSignal->connect(cb);
  262. }
  263. boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb )
  264. {
  265. if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
  266. return mMouseDownSignal->connect(cb);
  267. }
  268. boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb )
  269. {
  270. if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t();
  271. return mMouseUpSignal->connect(cb);
  272. }
  273. boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb )
  274. {
  275. if (!mHeldDownSignal) mHeldDownSignal = new commit_signal_t();
  276. return mHeldDownSignal->connect(cb);
  277. }
  278. // *TODO: Deprecate (for backwards compatability only)
  279. boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
  280. {
  281. return setClickedCallback(boost::bind(cb, data));
  282. }
  283. boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data )
  284. {
  285. return setMouseDownCallback(boost::bind(cb, data));
  286. }
  287. boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data )
  288. {
  289. return setMouseUpCallback(boost::bind(cb, data));
  290. }
  291. boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data )
  292. {
  293. return setHeldDownCallback(boost::bind(cb, data));
  294. }
  295. BOOL LLButton::postBuild()
  296. {
  297. autoResize();
  298. return TRUE;
  299. }
  300. BOOL LLButton::handleUnicodeCharHere(llwchar uni_char)
  301. {
  302. BOOL handled = FALSE;
  303. if(' ' == uni_char 
  304. && !gKeyboard->getKeyRepeated(' '))
  305. {
  306. if (mIsToggle)
  307. {
  308. toggleState();
  309. }
  310. LLUICtrl::onCommit();
  311. handled = TRUE;
  312. }
  313. return handled;
  314. }
  315. BOOL LLButton::handleKeyHere(KEY key, MASK mask )
  316. {
  317. BOOL handled = FALSE;
  318. if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
  319. {
  320. if (mIsToggle)
  321. {
  322. toggleState();
  323. }
  324. handled = TRUE;
  325. LLUICtrl::onCommit();
  326. }
  327. return handled;
  328. }
  329. BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
  330. {
  331. if (!childrenHandleMouseDown(x, y, mask))
  332. {
  333. // Route future Mouse messages here preemptively.  (Release on mouse up.)
  334. gFocusMgr.setMouseCapture( this );
  335. if (hasTabStop() && !getIsChrome())
  336. {
  337. setFocus(TRUE);
  338. }
  339. /*
  340.  * ATTENTION! This call fires another mouse down callback.
  341.  * If you wish to remove this call emit that signal directly
  342.  * by calling LLUICtrl::mMouseDownSignal(x, y, mask);
  343.  */
  344. LLUICtrl::handleMouseDown(x, y, mask);
  345. if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
  346. mMouseDownTimer.start();
  347. mMouseDownFrame = (S32) LLFrameTimer::getFrameCount();
  348. mMouseHeldDownCount = 0;
  349. if (getSoundFlags() & MOUSE_DOWN)
  350. {
  351. make_ui_sound("UISndClick");
  352. }
  353. }
  354. return TRUE;
  355. }
  356. BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
  357. {
  358. // We only handle the click if the click both started and ended within us
  359. if( hasMouseCapture() )
  360. {
  361. // Always release the mouse
  362. gFocusMgr.setMouseCapture( NULL );
  363. /*
  364.  * ATTENTION! This call fires another mouse up callback.
  365.  * If you wish to remove this call emit that signal directly
  366.  * by calling LLUICtrl::mMouseUpSignal(x, y, mask);
  367.  */
  368. LLUICtrl::handleMouseUp(x, y, mask);
  369. // Regardless of where mouseup occurs, handle callback
  370. if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
  371. resetMouseDownTimer();
  372. // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
  373. // If mouseup in the widget, it's been clicked
  374. if (pointInView(x, y))
  375. {
  376. if (getSoundFlags() & MOUSE_UP)
  377. {
  378. make_ui_sound("UISndClickRelease");
  379. }
  380. if (mIsToggle)
  381. {
  382. toggleState();
  383. }
  384. LLUICtrl::onCommit();
  385. }
  386. }
  387. else
  388. {
  389. childrenHandleMouseUp(x, y, mask);
  390. }
  391. return TRUE;
  392. }
  393. BOOL LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask)
  394. {
  395. if (!childrenHandleRightMouseDown(x, y, mask))
  396. {
  397. // Route future Mouse messages here preemptively.  (Release on mouse up.)
  398. gFocusMgr.setMouseCapture( this );
  399. if (hasTabStop() && !getIsChrome())
  400. {
  401. setFocus(TRUE);
  402. }
  403. // if (pointInView(x, y))
  404. // {
  405. // }
  406. }
  407. // send the mouse down signal
  408. LLUICtrl::handleRightMouseDown(x,y,mask);
  409. // *TODO: Return result of LLUICtrl call above?  Should defer to base class
  410. // but this might change the mouse handling of existing buttons in a bad way
  411. // if they are not mouse opaque.
  412. return TRUE;
  413. }
  414. BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask)
  415. {
  416. // We only handle the click if the click both started and ended within us
  417. if( hasMouseCapture() )
  418. {
  419. // Always release the mouse
  420. gFocusMgr.setMouseCapture( NULL );
  421. // if (pointInView(x, y))
  422. // {
  423. // mRightMouseUpSignal(this, x,y,mask);
  424. // }
  425. }
  426. else 
  427. {
  428. childrenHandleRightMouseUp(x, y, mask);
  429. }
  430. // send the mouse up signal
  431. LLUICtrl::handleRightMouseUp(x,y,mask);
  432. // *TODO: Return result of LLUICtrl call above?  Should defer to base class
  433. // but this might change the mouse handling of existing buttons in a bad way.
  434. // if they are not mouse opaque.
  435. return TRUE;
  436. }
  437. void LLButton::onMouseEnter(S32 x, S32 y, MASK mask)
  438. {
  439. LLUICtrl::onMouseEnter(x, y, mask);
  440. if (isInEnabledChain())
  441. mNeedsHighlight = TRUE;
  442. }
  443. void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
  444. {
  445. LLUICtrl::onMouseLeave(x, y, mask);
  446. mNeedsHighlight = FALSE;
  447. }
  448. void LLButton::setHighlight(bool b)
  449. {
  450. mNeedsHighlight = b;
  451. }
  452. BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
  453. {
  454. if (!childrenHandleHover(x, y, mask))
  455. {
  456. if (mMouseDownTimer.getStarted())
  457. {
  458. F32 elapsed = getHeldDownTime();
  459. if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame)
  460. {
  461. LLSD param;
  462. param["count"] = mMouseHeldDownCount++;
  463. if (mHeldDownSignal) (*mHeldDownSignal)(this, param);
  464. }
  465. }
  466. // We only handle the click if the click both started and ended within us
  467. getWindow()->setCursor(UI_CURSOR_ARROW);
  468. lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
  469. }
  470. return TRUE;
  471. }
  472. // virtual
  473. void LLButton::draw()
  474. {
  475. F32 alpha = getDrawContext().mAlpha;
  476. bool flash = FALSE;
  477. static LLUICachedControl<F32> button_flash_rate("ButtonFlashRate", 0);
  478. static LLUICachedControl<S32> button_flash_count("ButtonFlashCount", 0);
  479. if( mFlashing )
  480. {
  481. F32 elapsed = mFlashingTimer.getElapsedTimeF32();
  482. S32 flash_count = S32(elapsed * button_flash_rate * 2.f);
  483. // flash on or off?
  484. flash = (flash_count % 2 == 0) || flash_count > S32((F32)button_flash_count * 2.f);
  485. }
  486. bool pressed_by_keyboard = FALSE;
  487. if (hasFocus())
  488. {
  489. pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN));
  490. }
  491. // Unselected image assignments
  492. S32 local_mouse_x;
  493. S32 local_mouse_y;
  494. LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
  495. bool enabled = isInEnabledChain();
  496. bool pressed = pressed_by_keyboard 
  497. || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y))
  498. || mForcePressedState;
  499. bool selected = getToggleState();
  500. bool use_glow_effect = FALSE;
  501. LLColor4 glow_color = LLColor4::white;
  502. LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
  503. LLUIImage* imagep = NULL;
  504. if (pressed)
  505. {
  506. imagep = selected ? mImagePressedSelected : mImagePressed;
  507. }
  508. else if ( mNeedsHighlight )
  509. {
  510. if (selected)
  511. {
  512. if (mImageHoverSelected)
  513. {
  514. imagep = mImageHoverSelected;
  515. }
  516. else
  517. {
  518. imagep = mImageSelected;
  519. use_glow_effect = TRUE;
  520. }
  521. }
  522. else
  523. {
  524. if (mImageHoverUnselected)
  525. {
  526. imagep = mImageHoverUnselected;
  527. }
  528. else
  529. {
  530. imagep = mImageUnselected;
  531. use_glow_effect = TRUE;
  532. }
  533. }
  534. }
  535. else 
  536. {
  537. imagep = selected ? mImageSelected : mImageUnselected;
  538. }
  539. // Override if more data is available
  540. // HACK: Use gray checked state to mean either:
  541. //   enabled and tentative
  542. // or
  543. //   disabled but checked
  544. if (!mImageDisabledSelected.isNull() 
  545. && 
  546. ( (enabled && getTentative()) 
  547. || (!enabled && selected ) ) )
  548. {
  549. imagep = mImageDisabledSelected;
  550. }
  551. else if (!mImageDisabled.isNull() 
  552. && !enabled 
  553. && !selected)
  554. {
  555. imagep = mImageDisabled;
  556. }
  557. if (mFlashing)
  558. {
  559. LLColor4 flash_color = mFlashBgColor.get();
  560. use_glow_effect = TRUE;
  561. glow_type = LLRender::BT_ALPHA; // blend the glow
  562. if (mNeedsHighlight) // highlighted AND flashing
  563. glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity
  564. else
  565. glow_color = flash_color;
  566. }
  567. if (mNeedsHighlight && !imagep)
  568. {
  569. use_glow_effect = TRUE;
  570. }
  571. // Figure out appropriate color for the text
  572. LLColor4 label_color;
  573. // label changes when button state changes, not when pressed
  574. if ( enabled )
  575. {
  576. if ( getToggleState() )
  577. {
  578. label_color = mSelectedLabelColor.get();
  579. }
  580. else
  581. {
  582. label_color = mUnselectedLabelColor.get();
  583. }
  584. }
  585. else
  586. {
  587. if ( getToggleState() )
  588. {
  589. label_color = mDisabledSelectedLabelColor.get();
  590. }
  591. else
  592. {
  593. label_color = mDisabledLabelColor.get();
  594. }
  595. }
  596. // Unselected label assignments
  597. LLWString label;
  598. if( getToggleState() )
  599. {
  600. label = mSelectedLabel;
  601. }
  602. else
  603. {
  604. label = mUnselectedLabel;
  605. }
  606. // overlay with keyboard focus border
  607. if (hasFocus())
  608. {
  609. F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
  610. drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, llround(lerp(1.f, 3.f, lerp_amt)));
  611. }
  612. if (use_glow_effect)
  613. {
  614. mCurGlowStrength = lerp(mCurGlowStrength,
  615. mFlashing ? (flash? 1.0 : 0.0)
  616. : mHoverGlowStrength,
  617. LLCriticalDamp::getInterpolant(0.05f));
  618. }
  619. else
  620. {
  621. mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLCriticalDamp::getInterpolant(0.05f));
  622. }
  623. // Draw button image, if available.
  624. // Otherwise draw basic rectangular button.
  625. if (imagep != NULL)
  626. {
  627. // apply automatic 50% alpha fade to disabled image
  628. LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get();
  629. if ( mScaleImage)
  630. {
  631. imagep->draw(getLocalRect(), (enabled ? mImageColor.get() : disabled_color) % alpha  );
  632. if (mCurGlowStrength > 0.01f)
  633. {
  634. gGL.setSceneBlendType(glow_type);
  635. imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
  636. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  637. }
  638. }
  639. else
  640. {
  641. imagep->draw(0, 0, (enabled ? mImageColor.get() : disabled_color) % alpha );
  642. if (mCurGlowStrength > 0.01f)
  643. {
  644. gGL.setSceneBlendType(glow_type);
  645. imagep->drawSolid(0, 0, glow_color % (mCurGlowStrength * alpha));
  646. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  647. }
  648. }
  649. }
  650. else
  651. {
  652. // no image
  653. lldebugs << "No image for button " << getName() << llendl;
  654. // draw it in pink so we can find it
  655. gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1 % alpha, FALSE);
  656. }
  657. // let overlay image and text play well together
  658. S32 text_left = mLeftHPad;
  659. S32 text_right = getRect().getWidth() - mRightHPad;
  660. S32 text_width = getRect().getWidth() - mLeftHPad - mRightHPad;
  661. // draw overlay image
  662. if (mImageOverlay.notNull())
  663. {
  664. // get max width and height (discard level 0)
  665. S32 overlay_width = mImageOverlay->getWidth();
  666. S32 overlay_height = mImageOverlay->getHeight();
  667. F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f);
  668. overlay_width = llround((F32)overlay_width * scale_factor);
  669. overlay_height = llround((F32)overlay_height * scale_factor);
  670. S32 center_x = getLocalRect().getCenterX();
  671. S32 center_y = getLocalRect().getCenterY();
  672. //FUGLY HACK FOR "DEPRESSED" BUTTONS
  673. if (pressed)
  674. {
  675. center_y--;
  676. center_x++;
  677. }
  678. center_y += (mImageOverlayBottomPad - mImageOverlayTopPad);
  679. // fade out overlay images on disabled buttons
  680. LLColor4 overlay_color = mImageOverlayColor.get();
  681. if (!enabled)
  682. {
  683. overlay_color.mV[VALPHA] = 0.5f;
  684. }
  685. overlay_color.mV[VALPHA] *= alpha;
  686. switch(mImageOverlayAlignment)
  687. {
  688. case LLFontGL::LEFT:
  689. text_left += overlay_width + mImgOverlayLabelSpace;
  690. mImageOverlay->draw(
  691. mLeftHPad,
  692. center_y - (overlay_height / 2), 
  693. overlay_width, 
  694. overlay_height, 
  695. overlay_color);
  696. break;
  697. case LLFontGL::HCENTER:
  698. mImageOverlay->draw(
  699. center_x - (overlay_width / 2), 
  700. center_y - (overlay_height / 2), 
  701. overlay_width, 
  702. overlay_height, 
  703. overlay_color);
  704. break;
  705. case LLFontGL::RIGHT:
  706. text_right -= overlay_width + mImgOverlayLabelSpace;
  707. mImageOverlay->draw(
  708. getRect().getWidth() - mRightHPad - overlay_width,
  709. center_y - (overlay_height / 2), 
  710. overlay_width, 
  711. overlay_height, 
  712. overlay_color);
  713. break;
  714. default:
  715. // draw nothing
  716. break;
  717. }
  718. }
  719. // Draw label
  720. if( !label.empty() )
  721. {
  722. LLWStringUtil::trim(label);
  723. S32 x;
  724. switch( mHAlign )
  725. {
  726. case LLFontGL::RIGHT:
  727. x = text_right;
  728. break;
  729. case LLFontGL::HCENTER:
  730. x = getRect().getWidth() / 2;
  731. break;
  732. case LLFontGL::LEFT:
  733. default:
  734. x = text_left;
  735. break;
  736. }
  737. S32 y_offset = 2 + (getRect().getHeight() - 20)/2;
  738. if (pressed)
  739. {
  740. y_offset--;
  741. x++;
  742. }
  743. // *NOTE: mantipov: before mUseEllipses is implemented in EXT-279 U32_MAX has been passed as
  744. // max_chars.
  745. // LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value.
  746. // Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode.
  747. // Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars.
  748. mLastDrawCharsCount = mGLFont->render(label, 0,
  749. (F32)x,
  750. (F32)(mBottomVPad + y_offset),
  751. label_color % alpha,
  752. mHAlign, LLFontGL::BOTTOM,
  753. LLFontGL::NORMAL,
  754. mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,
  755. S32_MAX, text_width,
  756. NULL, mUseEllipses);
  757. }
  758. LLUICtrl::draw();
  759. }
  760. void LLButton::drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size)
  761. {
  762. if (imagep == NULL) return;
  763. if (mScaleImage)
  764. {
  765. imagep->drawBorder(getLocalRect(), color, size);
  766. }
  767. else
  768. {
  769. imagep->drawBorder(0, 0, color, size);
  770. }
  771. }
  772. BOOL LLButton::getToggleState() const
  773. {
  774.     return getValue().asBoolean();
  775. }
  776. void LLButton::setToggleState(BOOL b)
  777. {
  778. if( b != getToggleState() )
  779. {
  780. setControlValue(b); // will fire LLControlVariable callbacks (if any)
  781. setValue(b);        // may or may not be redundant
  782. // Unselected label assignments
  783. autoResize();
  784. }
  785. }
  786. void LLButton::setFlashing( BOOL b )
  787. if (b != mFlashing)
  788. {
  789. mFlashing = b; 
  790. mFlashingTimer.reset();
  791. }
  792. }
  793. BOOL LLButton::toggleState()
  794. {
  795.     bool flipped = ! getToggleState();
  796. setToggleState(flipped); 
  797. return flipped; 
  798. }
  799. void LLButton::setLabel( const LLStringExplicit& label )
  800. {
  801. setLabelUnselected(label);
  802. setLabelSelected(label);
  803. }
  804. //virtual
  805. BOOL LLButton::setLabelArg( const std::string& key, const LLStringExplicit& text )
  806. {
  807. mUnselectedLabel.setArg(key, text);
  808. mSelectedLabel.setArg(key, text);
  809. return TRUE;
  810. }
  811. void LLButton::setLabelUnselected( const LLStringExplicit& label )
  812. {
  813. mUnselectedLabel = label;
  814. }
  815. void LLButton::setLabelSelected( const LLStringExplicit& label )
  816. {
  817. mSelectedLabel = label;
  818. }
  819. void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
  820. {
  821. mImageUnselected = image;
  822. if (mImageUnselected.isNull())
  823. {
  824. llwarns << "Setting default button image for: " << getName() << " to NULL" << llendl;
  825. }
  826. }
  827. void LLButton::autoResize()
  828. {
  829. LLUIString label;
  830. if(getToggleState())
  831. {
  832. label = mSelectedLabel;
  833. }
  834. else
  835. {
  836. label = mUnselectedLabel;
  837. }
  838. resize(label);
  839. }
  840. void LLButton::resize(LLUIString label)
  841. {
  842. // get label length 
  843. S32 label_width = mGLFont->getWidth(label.getString());
  844. // get current btn length 
  845. S32 btn_width =getRect().getWidth();
  846.     // check if it need resize 
  847. if (mAutoResize == TRUE)
  848. if (btn_width - (mRightHPad + mLeftHPad) < label_width)
  849. {
  850. setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mLeft + label_width + mLeftHPad + mRightHPad , getRect().mBottom));
  851. }
  852. }
  853. void LLButton::setImages( const std::string &image_name, const std::string &selected_name )
  854. {
  855. setImageUnselected(LLUI::getUIImage(image_name));
  856. setImageSelected(LLUI::getUIImage(selected_name));
  857. }
  858. void LLButton::setImageSelected(LLPointer<LLUIImage> image)
  859. {
  860. mImageSelected = image;
  861. }
  862. void LLButton::setImageColor(const LLColor4& c)
  863. mImageColor = c; 
  864. }
  865. void LLButton::setColor(const LLColor4& color)
  866. {
  867. setImageColor(color);
  868. }
  869. void LLButton::setImageDisabled(LLPointer<LLUIImage> image)
  870. {
  871. mImageDisabled = image;
  872. mDisabledImageColor = mImageColor;
  873. mFadeWhenDisabled = TRUE;
  874. }
  875. void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
  876. {
  877. mImageDisabledSelected = image;
  878. mDisabledImageColor = mImageColor;
  879. mFadeWhenDisabled = TRUE;
  880. }
  881. void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image)
  882. {
  883. mImageHoverSelected = image;
  884. }
  885. void LLButton::setImageHoverUnselected(LLPointer<LLUIImage> image)
  886. {
  887. mImageHoverUnselected = image;
  888. }
  889. void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment, const LLColor4& color)
  890. {
  891. if (image_name.empty())
  892. {
  893. mImageOverlay = NULL;
  894. }
  895. else
  896. {
  897. mImageOverlay = LLUI::getUIImage(image_name);
  898. mImageOverlayAlignment = alignment;
  899. mImageOverlayColor = color;
  900. }
  901. }
  902. void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment, const LLColor4& color)
  903. {
  904. if (image_id.isNull())
  905. {
  906. mImageOverlay = NULL;
  907. }
  908. else
  909. {
  910. mImageOverlay = LLUI::getUIImageByID(image_id);
  911. mImageOverlayAlignment = alignment;
  912. mImageOverlayColor = color;
  913. }
  914. }
  915. void LLButton::onMouseCaptureLost()
  916. {
  917. resetMouseDownTimer();
  918. }
  919. //-------------------------------------------------------------------------
  920. // Utilities
  921. //-------------------------------------------------------------------------
  922. S32 round_up(S32 grid, S32 value)
  923. {
  924. S32 mod = value % grid;
  925. if (mod > 0)
  926. {
  927. // not even multiple
  928. return value + (grid - mod);
  929. }
  930. else
  931. {
  932. return value;
  933. }
  934. }
  935. void LLButton::addImageAttributeToXML(LLXMLNodePtr node, 
  936.   const std::string& image_name,
  937.   const LLUUID& image_id,
  938.   const std::string& xml_tag_name) const
  939. {
  940. if( !image_name.empty() )
  941. {
  942. node->createChild(xml_tag_name.c_str(), TRUE)->setStringValue(image_name);
  943. }
  944. else if( image_id != LLUUID::null )
  945. {
  946. node->createChild((xml_tag_name + "_id").c_str(), TRUE)->setUUIDValue(image_id);
  947. }
  948. }
  949. // static
  950. void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname)
  951. {
  952. bool floater_vis = LLFloaterReg::toggleInstance(sdname.asString());
  953. LLButton* button = dynamic_cast<LLButton*>(ctrl);
  954. if (button)
  955. button->setToggleState(floater_vis);
  956. }
  957. // static
  958. // Gets called once
  959. void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)
  960. {
  961. LLButton* button = dynamic_cast<LLButton*>(ctrl);
  962. if (!button)
  963. return;
  964. // Get the visibility control name for the floater
  965. std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
  966. // Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
  967. button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name));
  968. // Set the clicked callback to toggle the floater
  969. button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname));
  970. }
  971. // static
  972. void LLButton::setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)
  973. {
  974. LLButton* button = dynamic_cast<LLButton*>(ctrl);
  975. if (!button)
  976. return;
  977. // Get the visibility control name for the floater
  978. std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
  979. // Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
  980. button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name));
  981. // Set the clicked callback to toggle the floater
  982. button->setClickedCallback(boost::bind(&LLDockableFloater::toggleInstance, sdname));
  983. }
  984. // static
  985. void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname)
  986. {
  987. // search back through the button's parents for a panel
  988. // with a help_topic string defined
  989. std::string help_topic;
  990. if (LLUI::sHelpImpl &&
  991.     ctrl->findHelpTopic(help_topic))
  992. {
  993. LLUI::sHelpImpl->showTopic(help_topic);
  994. return; // success
  995. }
  996. // display an error if we can't find a help_topic string.
  997. // fix this by adding a help_topic attribute to the xui file
  998. LLNotificationsUtil::add("UnableToFindHelpTopic");
  999. }
  1000. void LLButton::resetMouseDownTimer()
  1001. {
  1002. mMouseDownTimer.stop();
  1003. mMouseDownTimer.reset();
  1004. }