diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/llui/llbutton.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/llui/llbutton.cpp')
-rw-r--r-- | indra/llui/llbutton.cpp | 2642 |
1 files changed, 1321 insertions, 1321 deletions
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index b343f5b4b4..e6c045250e 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -1,1321 +1,1321 @@ -
-/**
- * @file llbutton.cpp
- * @brief LLButton base class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#define LLBUTTON_CPP
-#include "llbutton.h"
-
-// Linden library includes
-#include "v4color.h"
-#include "llstring.h"
-
-// Project includes
-#include "llkeyboard.h"
-#include "llui.h"
-#include "lluiconstants.h"
-#include "llresmgr.h"
-#include "llcriticaldamp.h"
-#include "llfloater.h"
-#include "llfloaterreg.h"
-#include "llfocusmgr.h"
-#include "llwindow.h"
-#include "llnotificationsutil.h"
-#include "llrender.h"
-#include "lluictrlfactory.h"
-#include "lluiusage.h"
-#include "llhelp.h"
-#include "lldockablefloater.h"
-#include "llviewereventrecorder.h"
-
-static LLDefaultChildRegistry::Register<LLButton> r("button");
-
-// Compiler optimization, generate extern template
-template class LLButton* LLView::getChild<class LLButton>(
- const std::string& name, bool recurse) const;
-
-// globals
-S32 LLBUTTON_H_PAD = 4;
-S32 BTN_HEIGHT_SMALL= 23;
-S32 BTN_HEIGHT = 23;
-S32 BTN_DROP_SHADOW = 2;
-
-LLButton::Params::Params()
-: label_selected("label_selected"), // requires is_toggle true
- label_shadow("label_shadow", true),
- auto_resize("auto_resize", false),
- use_ellipses("use_ellipses", false),
- use_font_color("use_font_color", true),
- image_unselected("image_unselected"),
- image_selected("image_selected"),
- image_hover_selected("image_hover_selected"),
- image_hover_unselected("image_hover_unselected"),
- image_disabled_selected("image_disabled_selected"),
- image_disabled("image_disabled"),
- image_pressed("image_pressed"),
- image_pressed_selected("image_pressed_selected"),
- image_overlay("image_overlay"),
- image_overlay_alignment("image_overlay_alignment", std::string("center")),
- image_top_pad("image_top_pad"),
- image_bottom_pad("image_bottom_pad"),
- imgoverlay_label_space("imgoverlay_label_space", 1),
- label_color("label_color"),
- label_color_selected("label_color_selected"), // requires is_toggle true
- label_color_disabled("label_color_disabled"),
- label_color_disabled_selected("label_color_disabled_selected"),
- image_color("image_color"),
- image_color_disabled("image_color_disabled"),
- image_overlay_color("image_overlay_color", LLColor4::white % 0.75f),
- image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f),
- image_overlay_selected_color("image_overlay_selected_color", LLColor4::white),
- flash_color("flash_color"),
- pad_right("pad_right", LLBUTTON_H_PAD),
- pad_left("pad_left", LLBUTTON_H_PAD),
- pad_bottom("pad_bottom"),
- click_callback("click_callback"),
- mouse_down_callback("mouse_down_callback"),
- mouse_up_callback("mouse_up_callback"),
- mouse_held_callback("mouse_held_callback"),
- is_toggle("is_toggle", false),
- scale_image("scale_image", true),
- hover_glow_amount("hover_glow_amount"),
- commit_on_return("commit_on_return", true),
- commit_on_capture_lost("commit_on_capture_lost", false),
- display_pressed_state("display_pressed_state", true),
- use_draw_context_alpha("use_draw_context_alpha", true),
- badge("badge"),
- handle_right_mouse("handle_right_mouse"),
- held_down_delay("held_down_delay"),
- button_flash_enable("button_flash_enable", false),
- button_flash_count("button_flash_count"),
- button_flash_rate("button_flash_rate")
-{
- addSynonym(is_toggle, "toggle");
- changeDefault(initial_value, LLSD(false));
-}
-
-
-LLButton::LLButton(const LLButton::Params& p)
-: LLUICtrl(p),
- LLBadgeOwner(getHandle()),
- mMouseDownFrame(0),
- mMouseHeldDownCount(0),
- mBorderEnabled( false ),
- mFlashing( false ),
- mCurGlowStrength(0.f),
- mNeedsHighlight(false),
- mUnselectedLabel(p.label()),
- mSelectedLabel(p.label_selected()),
- mGLFont(p.font),
- mHeldDownDelay(p.held_down_delay.seconds), // seconds until held-down callback is called
- mHeldDownFrameDelay(p.held_down_delay.frames),
- mImageUnselected(p.image_unselected),
- mImageSelected(p.image_selected),
- mImageDisabled(p.image_disabled),
- mImageDisabledSelected(p.image_disabled_selected),
- mImageFlash(p.image_flash),
- mImagePressed(p.image_pressed),
- mImagePressedSelected(p.image_pressed_selected),
- mImageHoverSelected(p.image_hover_selected),
- mImageHoverUnselected(p.image_hover_unselected),
- mUnselectedLabelColor(p.label_color()),
- mSelectedLabelColor(p.label_color_selected()),
- mDisabledLabelColor(p.label_color_disabled()),
- mDisabledSelectedLabelColor(p.label_color_disabled_selected()),
- mImageColor(p.image_color()),
- mFlashBgColor(p.flash_color()),
- mDisabledImageColor(p.image_color_disabled()),
- mImageOverlay(p.image_overlay()),
- mImageOverlayColor(p.image_overlay_color()),
- mImageOverlayDisabledColor(p.image_overlay_disabled_color()),
- mImageOverlaySelectedColor(p.image_overlay_selected_color()),
- mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)),
- mImageOverlayTopPad(p.image_top_pad),
- mImageOverlayBottomPad(p.image_bottom_pad),
- mImgOverlayLabelSpace(p.imgoverlay_label_space),
- mIsToggle(p.is_toggle),
- mScaleImage(p.scale_image),
- mDropShadowedText(p.label_shadow),
- mAutoResize(p.auto_resize),
- mUseEllipses( p.use_ellipses ),
- mUseFontColor( p.use_font_color),
- mHAlign(p.font_halign),
- mLeftHPad(p.pad_left),
- mRightHPad(p.pad_right),
- mBottomVPad(p.pad_bottom),
- mHoverGlowStrength(p.hover_glow_amount),
- mCommitOnReturn(p.commit_on_return),
- mCommitOnCaptureLost(p.commit_on_capture_lost),
- mFadeWhenDisabled(false),
- mForcePressedState(false),
- mDisplayPressedState(p.display_pressed_state),
- mLastDrawCharsCount(0),
- mMouseDownSignal(NULL),
- mMouseUpSignal(NULL),
- mHeldDownSignal(NULL),
- mUseDrawContextAlpha(p.use_draw_context_alpha),
- mHandleRightMouse(p.handle_right_mouse),
- mFlashingTimer(NULL)
-{
- if (p.button_flash_enable)
- {
- // If optional parameter "p.button_flash_count" is not provided, LLFlashTimer will be
- // used instead it a "default" value from gSavedSettings.getS32("FlashCount")).
- // Likewise, missing "p.button_flash_rate" is replaced by gSavedSettings.getF32("FlashPeriod").
- // Note: flashing should be allowed in settings.xml (boolean key "EnableButtonFlashing").
- S32 flash_count = p.button_flash_count.isProvided()? p.button_flash_count : 0;
- F32 flash_rate = p.button_flash_rate.isProvided()? p.button_flash_rate : 0.0;
- mFlashingTimer = new LLFlashTimer ((LLFlashTimer::callback_t)NULL, flash_count, flash_rate);
- }
- else
- {
- mButtonFlashCount = p.button_flash_count;
- mButtonFlashRate = p.button_flash_rate;
- }
-
- static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
- static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>());
-
- if (!p.label_selected.isProvided())
- {
- mSelectedLabel = mUnselectedLabel;
- }
-
- // Hack to make sure there is space for at least one character
- if (getRect().mRight >= 0 && getRect().getWidth() > 0 &&
- getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
- {
- // Use old defaults
- mLeftHPad = llbutton_orig_h_pad;
- mRightHPad = llbutton_orig_h_pad;
- }
-
- mMouseDownTimer.stop();
-
- // if custom unselected button image provided...
- if (p.image_unselected != default_params.image_unselected)
- {
- //...fade it out for disabled image by default...
- if (p.image_disabled() == default_params.image_disabled() )
- {
- mImageDisabled = p.image_unselected;
- mFadeWhenDisabled = true;
- }
-
- if (p.image_pressed_selected == default_params.image_pressed_selected)
- {
- mImagePressedSelected = mImageUnselected;
- }
- }
-
- // if custom selected button image provided...
- if (p.image_selected != default_params.image_selected)
- {
- //...fade it out for disabled image by default...
- if (p.image_disabled_selected() == default_params.image_disabled_selected())
- {
- mImageDisabledSelected = p.image_selected;
- mFadeWhenDisabled = true;
- }
-
- if (p.image_pressed == default_params.image_pressed)
- {
- mImagePressed = mImageSelected;
- }
- }
-
- if (!p.image_pressed.isProvided())
- {
- mImagePressed = mImageSelected;
- }
-
- if (!p.image_pressed_selected.isProvided())
- {
- mImagePressedSelected = mImageUnselected;
- }
-
- if (mImageUnselected.isNull())
- {
- LL_WARNS() << "Button: " << getName() << " with no image!" << LL_ENDL;
- }
-
- if (p.click_callback.isProvided())
- {
- setCommitCallback(initCommitCallback(p.click_callback)); // alias -> commit_callback
- }
- if (p.mouse_down_callback.isProvided())
- {
- setMouseDownCallback(initCommitCallback(p.mouse_down_callback));
- }
- if (p.mouse_up_callback.isProvided())
- {
- setMouseUpCallback(initCommitCallback(p.mouse_up_callback));
- }
- if (p.mouse_held_callback.isProvided())
- {
- setHeldDownCallback(initCommitCallback(p.mouse_held_callback));
- }
-
- if (p.badge.isProvided())
- {
- LLBadgeOwner::initBadgeParams(p.badge());
- }
-}
-
-LLButton::~LLButton()
-{
- delete mMouseDownSignal;
- delete mMouseUpSignal;
- delete mHeldDownSignal;
-
- if (mFlashingTimer)
- {
- mFlashingTimer->unset();
- }
-}
-
-// HACK: Committing a button is the same as instantly clicking it.
-// virtual
-void LLButton::onCommit()
-{
- // WARNING: Sometimes clicking a button destroys the floater or
- // panel containing it. Therefore we need to call LLUICtrl::onCommit()
- // LAST, otherwise this becomes deleted memory.
-
- if (mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
-
- if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
-
- if (getSoundFlags() & MOUSE_DOWN)
- {
- make_ui_sound("UISndClick");
- }
-
- if (getSoundFlags() & MOUSE_UP)
- {
- make_ui_sound("UISndClickRelease");
- }
-
- if (mIsToggle)
- {
- toggleState();
- }
-
- // do this last, as it can result in destroying this button
- LLUICtrl::onCommit();
-}
-
-boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb)
-{
- return setClickedCallback(initCommitCallback(cb));
-}
-boost::signals2::connection LLButton::setMouseDownCallback(const CommitCallbackParam& cb)
-{
- return setMouseDownCallback(initCommitCallback(cb));
-}
-boost::signals2::connection LLButton::setMouseUpCallback(const CommitCallbackParam& cb)
-{
- return setMouseUpCallback(initCommitCallback(cb));
-}
-boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackParam& cb)
-{
- return setHeldDownCallback(initCommitCallback(cb));
-}
-
-
-boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mCommitSignal) mCommitSignal = new commit_signal_t();
- return mCommitSignal->connect(cb);
-}
-boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
- return mMouseDownSignal->connect(cb);
-}
-boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t();
- return mMouseUpSignal->connect(cb);
-}
-boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mHeldDownSignal) mHeldDownSignal = new commit_signal_t();
- return mHeldDownSignal->connect(cb);
-}
-
-
-// *TODO: Deprecate (for backwards compatibility only)
-boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
-{
- return setClickedCallback(boost::bind(cb, data));
-}
-boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data )
-{
- return setMouseDownCallback(boost::bind(cb, data));
-}
-boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data )
-{
- return setMouseUpCallback(boost::bind(cb, data));
-}
-boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data )
-{
- return setHeldDownCallback(boost::bind(cb, data));
-}
-
-bool LLButton::postBuild()
-{
- autoResize();
-
- addBadgeToParentHolder();
-
- return LLUICtrl::postBuild();
-}
-
-bool LLButton::handleUnicodeCharHere(llwchar uni_char)
-{
- bool handled = false;
- if(' ' == uni_char
- && !gKeyboard->getKeyRepeated(' '))
- {
- if (mIsToggle)
- {
- toggleState();
- }
-
- LLUICtrl::onCommit();
-
- handled = true;
- }
- return handled;
-}
-
-bool LLButton::handleKeyHere(KEY key, MASK mask )
-{
- bool handled = false;
- if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
- {
- if (mIsToggle)
- {
- toggleState();
- }
-
- handled = true;
-
- LLUICtrl::onCommit();
- }
- return handled;
-}
-
-
-bool LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
-{
- if (!childrenHandleMouseDown(x, y, mask))
- {
- // Route future Mouse messages here preemptively. (Release on mouse up.)
- gFocusMgr.setMouseCapture( this );
-
- if (hasTabStop() && !getIsChrome())
- {
- setFocus(true);
- }
-
- if (!mFunctionName.empty())
- {
- LL_DEBUGS("UIUsage") << "calling mouse down function " << mFunctionName << LL_ENDL;
- LLUIUsage::instance().logCommand(mFunctionName);
- LLUIUsage::instance().logControl(getPathname());
- }
-
- /*
- * ATTENTION! This call fires another mouse down callback.
- * If you wish to remove this call emit that signal directly
- * by calling LLUICtrl::mMouseDownSignal(x, y, mask);
- */
- LLUICtrl::handleMouseDown(x, y, mask);
-
- LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
-
- if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
-
- mMouseDownTimer.start();
- mMouseDownFrame = (S32) LLFrameTimer::getFrameCount();
- mMouseHeldDownCount = 0;
-
-
- if (getSoundFlags() & MOUSE_DOWN)
- {
- make_ui_sound("UISndClick");
- }
- }
- return true;
-}
-
-
-bool LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
-{
- // We only handle the click if the click both started and ended within us
- if( hasMouseCapture() )
- {
- // reset timers before focus change, to not cause
- // additional commits if mCommitOnCaptureLost.
- resetMouseDownTimer();
-
- // Always release the mouse
- gFocusMgr.setMouseCapture( NULL );
-
- /*
- * ATTENTION! This call fires another mouse up callback.
- * If you wish to remove this call emit that signal directly
- * by calling LLUICtrl::mMouseUpSignal(x, y, mask);
- */
- LLUICtrl::handleMouseUp(x, y, mask);
- LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
-
- // Regardless of where mouseup occurs, handle callback
- if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
-
- // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
- // If mouseup in the widget, it's been clicked
- if (pointInView(x, y))
- {
- if (getSoundFlags() & MOUSE_UP)
- {
- make_ui_sound("UISndClickRelease");
- }
-
- if (mIsToggle)
- {
- toggleState();
- }
-
- LLUICtrl::onCommit();
- }
- }
- else
- {
- childrenHandleMouseUp(x, y, mask);
- }
-
- return true;
-}
-
-bool LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- if (mHandleRightMouse && !childrenHandleRightMouseDown(x, y, mask))
- {
- // Route future Mouse messages here preemptively. (Release on mouse up.)
- gFocusMgr.setMouseCapture( this );
-
- if (hasTabStop() && !getIsChrome())
- {
- setFocus(true);
- }
-
-// if (pointInView(x, y))
-// {
-// }
- // send the mouse down signal
- LLUICtrl::handleRightMouseDown(x,y,mask);
- // *TODO: Return result of LLUICtrl call above? Should defer to base class
- // but this might change the mouse handling of existing buttons in a bad way
- // if they are not mouse opaque.
- }
-
- return true;
-}
-
-bool LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask)
-{
- if (mHandleRightMouse)
- {
- // We only handle the click if the click both started and ended within us
- if( hasMouseCapture() )
- {
- // Always release the mouse
- gFocusMgr.setMouseCapture( NULL );
-
- // if (pointInView(x, y))
- // {
- // mRightMouseUpSignal(this, x,y,mask);
- // }
- }
- else
- {
- childrenHandleRightMouseUp(x, y, mask);
- }
-
- // send the mouse up signal
- LLUICtrl::handleRightMouseUp(x,y,mask);
- // *TODO: Return result of LLUICtrl call above? Should defer to base class
- // but this might change the mouse handling of existing buttons in a bad way.
- // if they are not mouse opaque.
- }
- return true;
-}
-
-void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
-{
- LLUICtrl::onMouseLeave(x, y, mask);
-
- mNeedsHighlight = false;
-}
-
-void LLButton::setHighlight(bool b)
-{
- mNeedsHighlight = b;
-}
-
-bool LLButton::handleHover(S32 x, S32 y, MASK mask)
-{
- if (isInEnabledChain()
- && (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this))
- mNeedsHighlight = true;
-
- if (!childrenHandleHover(x, y, mask))
- {
- if (mMouseDownTimer.getStarted())
- {
- F32 elapsed = getHeldDownTime();
- if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame)
- {
- LLSD param;
- param["count"] = mMouseHeldDownCount++;
- if (mHeldDownSignal) (*mHeldDownSignal)(this, param);
- }
- }
-
- // We only handle the click if the click both started and ended within us
- getWindow()->setCursor(UI_CURSOR_ARROW);
- LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL;
- }
- return true;
-}
-
-void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height)
-{
- overlay_width = mImageOverlay->getWidth();
- overlay_height = mImageOverlay->getHeight();
-
- F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f);
- overlay_width = ll_round((F32)overlay_width * scale_factor);
- overlay_height = ll_round((F32)overlay_height * scale_factor);
-}
-
-
-// virtual
-void LLButton::draw()
-{
- static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::getInstance()->mSettingGroups["config"], "EnableButtonFlashing", true);
- F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
-
- bool pressed_by_keyboard = false;
- if (hasFocus())
- {
- pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN));
- }
-
- bool mouse_pressed_and_over = false;
- if (hasMouseCapture())
- {
- S32 local_mouse_x ;
- S32 local_mouse_y;
- LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
- mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y);
- }
-
- bool enabled = isInEnabledChain();
-
- bool pressed = pressed_by_keyboard
- || mouse_pressed_and_over
- || mForcePressedState;
- bool selected = getToggleState();
-
- bool use_glow_effect = false;
- LLColor4 highlighting_color = LLColor4::white;
- LLColor4 glow_color = LLColor4::white;
- LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
- LLUIImage* imagep = NULL;
- LLUIImage* image_glow = NULL;
-
- // Cancel sticking of color, if the button is pressed,
- // or when a flashing of the previously selected button is ended
- if (mFlashingTimer
- && ((selected && !mFlashingTimer->isFlashingInProgress() && !mForceFlashing) || pressed))
- {
- mFlashing = false;
- }
-
- bool flash = mFlashing && sEnableButtonFlashing;
-
- if (pressed && mDisplayPressedState)
- {
- imagep = selected ? mImagePressedSelected : mImagePressed;
- }
- else if ( mNeedsHighlight )
- {
- if (selected)
- {
- if (mImageHoverSelected)
- {
- imagep = mImageHoverSelected;
- }
- else
- {
- imagep = mImageSelected;
- use_glow_effect = true;
- }
- }
- else
- {
- if (mImageHoverUnselected)
- {
- imagep = mImageHoverUnselected;
- }
- else
- {
- imagep = mImageUnselected;
- use_glow_effect = true;
- }
- }
- }
- else
- {
- imagep = selected ? mImageSelected : mImageUnselected;
- }
-
- // Override if more data is available
- // HACK: Use gray checked state to mean either:
- // enabled and tentative
- // or
- // disabled but checked
- if (!mImageDisabledSelected.isNull()
- &&
- ( (enabled && getTentative())
- || (!enabled && selected ) ) )
- {
- imagep = mImageDisabledSelected;
- }
- else if (!mImageDisabled.isNull()
- && !enabled
- && !selected)
- {
- imagep = mImageDisabled;
- }
-
- image_glow = imagep;
-
- if (mFlashing)
- {
- if (flash && mImageFlash)
- {
- // if button should flash and we have icon for flashing, use it as image for button
- image_glow = mImageFlash;
- }
-
- // provide fade-in and fade-out via flash_color
- if (mFlashingTimer)
- {
- LLColor4 flash_color = mFlashBgColor.get();
- use_glow_effect = true;
- glow_type = LLRender::BT_ALPHA; // blend the glow
-
- if (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress())
- {
- glow_color = flash_color;
- }
- else if (mNeedsHighlight)
- {
- glow_color = highlighting_color;
- }
- else
- {
- // will fade from highlight color
- glow_color = flash_color;
- }
- }
- }
-
- if (mNeedsHighlight && !imagep)
- {
- use_glow_effect = true;
- }
-
- // Figure out appropriate color for the text
- LLColor4 label_color;
-
- // label changes when button state changes, not when pressed
- if ( enabled )
- {
- if ( getToggleState() )
- {
- label_color = mSelectedLabelColor.get();
- }
- else
- {
- label_color = mUnselectedLabelColor.get();
- }
- }
- else
- {
- if ( getToggleState() )
- {
- label_color = mDisabledSelectedLabelColor.get();
- }
- else
- {
- label_color = mDisabledLabelColor.get();
- }
- }
-
- // Highlight if needed
- if( ll::ui::SearchableControl::getHighlighted() )
- label_color = ll::ui::SearchableControl::getHighlightColor();
-
- // Unselected label assignments
- LLWString label = getCurrentLabel();
-
- // overlay with keyboard focus border
- if (hasFocus())
- {
- F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
- drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, ll_round(lerp(1.f, 3.f, lerp_amt)));
- }
-
- if (use_glow_effect)
- {
- mCurGlowStrength = lerp(mCurGlowStrength,
- mFlashing ? (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress() || mNeedsHighlight? 1.f : 0.f) : mHoverGlowStrength,
- LLSmoothInterpolation::getInterpolant(0.05f));
- }
- else
- {
- mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f));
- }
-
- // Draw button image, if available.
- // Otherwise draw basic rectangular button.
- if (imagep != NULL)
- {
- // apply automatic 50% alpha fade to disabled image
- LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get();
- if ( mScaleImage)
- {
- imagep->draw(getLocalRect(), (enabled ? mImageColor.get() : disabled_color) % alpha );
- if (mCurGlowStrength > 0.01f)
- {
- gGL.setSceneBlendType(glow_type);
- image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
- }
- else
- {
- S32 y = getLocalRect().getHeight() - imagep->getHeight();
- imagep->draw(0, y, (enabled ? mImageColor.get() : disabled_color) % alpha);
- if (mCurGlowStrength > 0.01f)
- {
- gGL.setSceneBlendType(glow_type);
- image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha));
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
- }
- }
- else
- {
- // no image
- LL_DEBUGS() << "No image for button " << getName() << LL_ENDL;
- // draw it in pink so we can find it
- gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1 % alpha, false);
- }
-
- // let overlay image and text play well together
- S32 text_left = mLeftHPad;
- S32 text_right = getRect().getWidth() - mRightHPad;
- S32 text_width = getRect().getWidth() - mLeftHPad - mRightHPad;
-
- // draw overlay image
- if (mImageOverlay.notNull())
- {
- // get max width and height (discard level 0)
- S32 overlay_width;
- S32 overlay_height;
-
- getOverlayImageSize(overlay_width, overlay_height);
-
- S32 center_x = getLocalRect().getCenterX();
- S32 center_y = getLocalRect().getCenterY();
-
- //FUGLY HACK FOR "DEPRESSED" BUTTONS
- if (pressed && mDisplayPressedState)
- {
- center_y--;
- center_x++;
- }
-
- center_y += (mImageOverlayBottomPad - mImageOverlayTopPad);
- // fade out overlay images on disabled buttons
- LLColor4 overlay_color = mImageOverlayColor.get();
- if (!enabled)
- {
- overlay_color = mImageOverlayDisabledColor.get();
- }
- else if (getToggleState())
- {
- overlay_color = mImageOverlaySelectedColor.get();
- }
- overlay_color.mV[VALPHA] *= alpha;
-
- switch(mImageOverlayAlignment)
- {
- case LLFontGL::LEFT:
- text_left += overlay_width + mImgOverlayLabelSpace;
- text_width -= overlay_width + mImgOverlayLabelSpace;
- mImageOverlay->draw(
- mLeftHPad,
- center_y - (overlay_height / 2),
- overlay_width,
- overlay_height,
- overlay_color);
- break;
- case LLFontGL::HCENTER:
- mImageOverlay->draw(
- center_x - (overlay_width / 2),
- center_y - (overlay_height / 2),
- overlay_width,
- overlay_height,
- overlay_color);
- break;
- case LLFontGL::RIGHT:
- text_right -= overlay_width + mImgOverlayLabelSpace;
- text_width -= overlay_width + mImgOverlayLabelSpace;
- mImageOverlay->draw(
- getRect().getWidth() - mRightHPad - overlay_width,
- center_y - (overlay_height / 2),
- overlay_width,
- overlay_height,
- overlay_color);
- break;
- default:
- // draw nothing
- break;
- }
- }
-
- // Draw label
- if( !label.empty() )
- {
- LLWStringUtil::trim(label);
-
- S32 x;
- switch( mHAlign )
- {
- case LLFontGL::RIGHT:
- x = text_right;
- break;
- case LLFontGL::HCENTER:
- x = text_left + (text_width / 2);
- break;
- case LLFontGL::LEFT:
- default:
- x = text_left;
- break;
- }
-
- if (pressed && mDisplayPressedState)
- {
- x++;
- }
-
- // *NOTE: mantipov: before mUseEllipses is implemented in EXT-279 U32_MAX has been passed as
- // max_chars.
- // LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value.
- // Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode.
- // Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars.
- mLastDrawCharsCount = mGLFont->render(label, 0,
- (F32)x,
- (F32)(getRect().getHeight() / 2 + mBottomVPad),
- label_color % alpha,
- mHAlign, LLFontGL::VCENTER,
- LLFontGL::NORMAL,
- mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,
- S32_MAX, text_width,
- NULL, mUseEllipses, mUseFontColor);
- }
-
- LLUICtrl::draw();
-}
-
-void LLButton::drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size)
-{
- if (imagep == NULL) return;
- if (mScaleImage)
- {
- imagep->drawBorder(getLocalRect(), color, size);
- }
- else
- {
- S32 y = getLocalRect().getHeight() - imagep->getHeight();
- imagep->drawBorder(0, y, color, size);
- }
-}
-
-bool LLButton::getToggleState() const
-{
- return getValue().asBoolean();
-}
-
-void LLButton::setToggleState(bool b)
-{
- if( b != getToggleState() )
- {
- setControlValue(b); // will fire LLControlVariable callbacks (if any)
- setValue(b); // may or may not be redundant
- setFlashing(false); // stop flash state whenever the selected/unselected state if reset
- // Unselected label assignments
- autoResize();
- }
-}
-
-void LLButton::setFlashing(bool b, bool force_flashing/* = false */)
-{
- mForceFlashing = force_flashing;
- if (mFlashingTimer)
- {
- mFlashing = b;
- (b ? mFlashingTimer->startFlashing() : mFlashingTimer->stopFlashing());
- }
- else if (b != mFlashing)
- {
- mFlashing = b;
- mFrameTimer.reset();
- }
-}
-
-bool LLButton::toggleState()
-{
- bool flipped = ! getToggleState();
- setToggleState(flipped);
-
- return flipped;
-}
-
-void LLButton::setLabel( const std::string& label )
-{
- mUnselectedLabel = mSelectedLabel = label;
-}
-
-void LLButton::setLabel( const LLUIString& label )
-{
- mUnselectedLabel = mSelectedLabel = label;
-}
-
-void LLButton::setLabel( const LLStringExplicit& label )
-{
- setLabelUnselected(label);
- setLabelSelected(label);
-}
-
-//virtual
-bool LLButton::setLabelArg( const std::string& key, const LLStringExplicit& text )
-{
- mUnselectedLabel.setArg(key, text);
- mSelectedLabel.setArg(key, text);
- return true;
-}
-
-void LLButton::setLabelUnselected( const LLStringExplicit& label )
-{
- mUnselectedLabel = label;
-}
-
-void LLButton::setLabelSelected( const LLStringExplicit& label )
-{
- mSelectedLabel = label;
-}
-
-bool LLButton::labelIsTruncated() const
-{
- return getCurrentLabel().getString().size() > mLastDrawCharsCount;
-}
-
-const LLUIString& LLButton::getCurrentLabel() const
-{
- return getToggleState() ? mSelectedLabel : mUnselectedLabel;
-}
-
-void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
-{
- mImageUnselected = image;
- if (mImageUnselected.isNull())
- {
- LL_WARNS() << "Setting default button image for: " << getName() << " to NULL" << LL_ENDL;
- }
-}
-
-void LLButton::autoResize()
-{
- resize(getCurrentLabel());
-}
-
-void LLButton::resize(LLUIString label)
-{
- // get label length
- S32 label_width = mGLFont->getWidth(label.getString());
- // get current btn length
- S32 btn_width =getRect().getWidth();
- // check if it need resize
- if (mAutoResize)
- {
- S32 min_width = label_width + mLeftHPad + mRightHPad;
- if (mImageOverlay)
- {
- S32 overlay_width = mImageOverlay->getWidth();
- F32 scale_factor = (getRect().getHeight() - (mImageOverlayBottomPad + mImageOverlayTopPad)) / (F32)mImageOverlay->getHeight();
- overlay_width = ll_round((F32)overlay_width * scale_factor);
-
- switch(mImageOverlayAlignment)
- {
- case LLFontGL::LEFT:
- case LLFontGL::RIGHT:
- min_width += overlay_width + mImgOverlayLabelSpace;
- break;
- case LLFontGL::HCENTER:
- min_width = llmax(min_width, overlay_width + mLeftHPad + mRightHPad);
- break;
- default:
- // draw nothing
- break;
- }
- }
- if (btn_width < min_width)
- {
- reshape(min_width, getRect().getHeight());
- }
- }
-}
-void LLButton::setImages( const std::string &image_name, const std::string &selected_name )
-{
- setImageUnselected(LLUI::getUIImage(image_name));
- setImageSelected(LLUI::getUIImage(selected_name));
-}
-
-void LLButton::setImageSelected(LLPointer<LLUIImage> image)
-{
- mImageSelected = image;
-}
-
-void LLButton::setImageColor(const LLColor4& c)
-{
- mImageColor = c;
-}
-
-void LLButton::setColor(const LLColor4& color)
-{
- setImageColor(color);
-}
-
-void LLButton::setImageDisabled(LLPointer<LLUIImage> image)
-{
- mImageDisabled = image;
- mDisabledImageColor = mImageColor;
- mFadeWhenDisabled = true;
-}
-
-void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
-{
- mImageDisabledSelected = image;
- mDisabledImageColor = mImageColor;
- mFadeWhenDisabled = true;
-}
-
-void LLButton::setImagePressed(LLPointer<LLUIImage> image)
-{
- mImagePressed = image;
-}
-
-void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image)
-{
- mImageHoverSelected = image;
-}
-
-void LLButton::setImageHoverUnselected(LLPointer<LLUIImage> image)
-{
- mImageHoverUnselected = image;
-}
-
-void LLButton::setImageFlash(LLPointer<LLUIImage> image)
-{
- mImageFlash = image;
-}
-
-void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment, const LLColor4& color)
-{
- if (image_name.empty())
- {
- mImageOverlay = NULL;
- }
- else
- {
- mImageOverlay = LLUI::getUIImage(image_name);
- mImageOverlayAlignment = alignment;
- mImageOverlayColor = color;
- }
-}
-
-void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment, const LLColor4& color)
-{
- if (image_id.isNull())
- {
- mImageOverlay = NULL;
- }
- else
- {
- mImageOverlay = LLUI::getUIImageByID(image_id);
- mImageOverlayAlignment = alignment;
- mImageOverlayColor = color;
- }
-}
-
-void LLButton::onMouseCaptureLost()
-{
- if (mCommitOnCaptureLost
- && mMouseDownTimer.getStarted())
- {
- if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
-
- if (mIsToggle)
- {
- toggleState();
- }
-
- LLUICtrl::onCommit();
- }
- resetMouseDownTimer();
-}
-
-//-------------------------------------------------------------------------
-// Utilities
-//-------------------------------------------------------------------------
-S32 round_up(S32 grid, S32 value)
-{
- S32 mod = value % grid;
-
- if (mod > 0)
- {
- // not even multiple
- return value + (grid - mod);
- }
- else
- {
- return value;
- }
-}
-
-void LLButton::addImageAttributeToXML(LLXMLNodePtr node,
- const std::string& image_name,
- const LLUUID& image_id,
- const std::string& xml_tag_name) const
-{
- if( !image_name.empty() )
- {
- node->createChild(xml_tag_name.c_str(), true)->setStringValue(image_name);
- }
- else if( image_id != LLUUID::null )
- {
- node->createChild((xml_tag_name + "_id").c_str(), true)->setUUIDValue(image_id);
- }
-}
-
-
-// static
-void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname)
-{
- bool floater_vis = LLFloaterReg::toggleInstance(sdname.asString());
- LLButton* button = dynamic_cast<LLButton*>(ctrl);
- if (button)
- button->setToggleState(floater_vis);
-}
-
-// static
-// Gets called once
-void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)
-{
- LLButton* button = dynamic_cast<LLButton*>(ctrl);
- if (!button)
- return;
- // Get the visibility control name for the floater
- std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
- // Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
- button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
- // Set the clicked callback to toggle the floater
- button->setClickedCallback(boost::bind(&LLFloaterReg::toggleInstance, sdname, LLSD()));
-}
-
-// static
-void LLButton::setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)
-{
- LLButton* button = dynamic_cast<LLButton*>(ctrl);
- if (!button)
- return;
- // Get the visibility control name for the floater
- std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
- // Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
- button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
- // Set the clicked callback to toggle the floater
- button->setClickedCallback(boost::bind(&LLDockableFloater::toggleInstance, sdname));
-}
-
-// static
-void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname)
-{
- // search back through the button's parents for a panel
- // with a help_topic string defined
- std::string help_topic;
- if (LLUI::getInstance()->mHelpImpl &&
- ctrl->findHelpTopic(help_topic))
- {
- LLUI::getInstance()->mHelpImpl->showTopic(help_topic);
- return; // success
- }
-
- // display an error if we can't find a help_topic string.
- // fix this by adding a help_topic attribute to the xui file
- LLNotificationsUtil::add("UnableToFindHelpTopic");
-}
-
-void LLButton::resetMouseDownTimer()
-{
- mMouseDownTimer.stop();
- mMouseDownTimer.reset();
-}
-
-bool LLButton::handleDoubleClick(S32 x, S32 y, MASK mask)
-{
- // just treat a double click as a second click
- return handleMouseDown(x, y, mask);
-}
+ +/** + * @file llbutton.cpp + * @brief LLButton base class + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#define LLBUTTON_CPP +#include "llbutton.h" + +// Linden library includes +#include "v4color.h" +#include "llstring.h" + +// Project includes +#include "llkeyboard.h" +#include "llui.h" +#include "lluiconstants.h" +#include "llresmgr.h" +#include "llcriticaldamp.h" +#include "llfloater.h" +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llwindow.h" +#include "llnotificationsutil.h" +#include "llrender.h" +#include "lluictrlfactory.h" +#include "lluiusage.h" +#include "llhelp.h" +#include "lldockablefloater.h" +#include "llviewereventrecorder.h" + +static LLDefaultChildRegistry::Register<LLButton> r("button"); + +// Compiler optimization, generate extern template +template class LLButton* LLView::getChild<class LLButton>( + const std::string& name, bool recurse) const; + +// globals +S32 LLBUTTON_H_PAD = 4; +S32 BTN_HEIGHT_SMALL= 23; +S32 BTN_HEIGHT = 23; +S32 BTN_DROP_SHADOW = 2; + +LLButton::Params::Params() +: label_selected("label_selected"), // requires is_toggle true + label_shadow("label_shadow", true), + auto_resize("auto_resize", false), + use_ellipses("use_ellipses", false), + use_font_color("use_font_color", true), + image_unselected("image_unselected"), + image_selected("image_selected"), + image_hover_selected("image_hover_selected"), + image_hover_unselected("image_hover_unselected"), + image_disabled_selected("image_disabled_selected"), + image_disabled("image_disabled"), + image_pressed("image_pressed"), + image_pressed_selected("image_pressed_selected"), + image_overlay("image_overlay"), + image_overlay_alignment("image_overlay_alignment", std::string("center")), + image_top_pad("image_top_pad"), + image_bottom_pad("image_bottom_pad"), + imgoverlay_label_space("imgoverlay_label_space", 1), + label_color("label_color"), + label_color_selected("label_color_selected"), // requires is_toggle true + label_color_disabled("label_color_disabled"), + label_color_disabled_selected("label_color_disabled_selected"), + image_color("image_color"), + image_color_disabled("image_color_disabled"), + image_overlay_color("image_overlay_color", LLColor4::white % 0.75f), + image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f), + image_overlay_selected_color("image_overlay_selected_color", LLColor4::white), + flash_color("flash_color"), + pad_right("pad_right", LLBUTTON_H_PAD), + pad_left("pad_left", LLBUTTON_H_PAD), + pad_bottom("pad_bottom"), + click_callback("click_callback"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback"), + mouse_held_callback("mouse_held_callback"), + is_toggle("is_toggle", false), + scale_image("scale_image", true), + hover_glow_amount("hover_glow_amount"), + commit_on_return("commit_on_return", true), + commit_on_capture_lost("commit_on_capture_lost", false), + display_pressed_state("display_pressed_state", true), + use_draw_context_alpha("use_draw_context_alpha", true), + badge("badge"), + handle_right_mouse("handle_right_mouse"), + held_down_delay("held_down_delay"), + button_flash_enable("button_flash_enable", false), + button_flash_count("button_flash_count"), + button_flash_rate("button_flash_rate") +{ + addSynonym(is_toggle, "toggle"); + changeDefault(initial_value, LLSD(false)); +} + + +LLButton::LLButton(const LLButton::Params& p) +: LLUICtrl(p), + LLBadgeOwner(getHandle()), + mMouseDownFrame(0), + mMouseHeldDownCount(0), + mBorderEnabled( false ), + mFlashing( false ), + mCurGlowStrength(0.f), + mNeedsHighlight(false), + mUnselectedLabel(p.label()), + mSelectedLabel(p.label_selected()), + mGLFont(p.font), + mHeldDownDelay(p.held_down_delay.seconds), // seconds until held-down callback is called + mHeldDownFrameDelay(p.held_down_delay.frames), + mImageUnselected(p.image_unselected), + mImageSelected(p.image_selected), + mImageDisabled(p.image_disabled), + mImageDisabledSelected(p.image_disabled_selected), + mImageFlash(p.image_flash), + mImagePressed(p.image_pressed), + mImagePressedSelected(p.image_pressed_selected), + mImageHoverSelected(p.image_hover_selected), + mImageHoverUnselected(p.image_hover_unselected), + mUnselectedLabelColor(p.label_color()), + mSelectedLabelColor(p.label_color_selected()), + mDisabledLabelColor(p.label_color_disabled()), + mDisabledSelectedLabelColor(p.label_color_disabled_selected()), + mImageColor(p.image_color()), + mFlashBgColor(p.flash_color()), + mDisabledImageColor(p.image_color_disabled()), + mImageOverlay(p.image_overlay()), + mImageOverlayColor(p.image_overlay_color()), + mImageOverlayDisabledColor(p.image_overlay_disabled_color()), + mImageOverlaySelectedColor(p.image_overlay_selected_color()), + mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)), + mImageOverlayTopPad(p.image_top_pad), + mImageOverlayBottomPad(p.image_bottom_pad), + mImgOverlayLabelSpace(p.imgoverlay_label_space), + mIsToggle(p.is_toggle), + mScaleImage(p.scale_image), + mDropShadowedText(p.label_shadow), + mAutoResize(p.auto_resize), + mUseEllipses( p.use_ellipses ), + mUseFontColor( p.use_font_color), + mHAlign(p.font_halign), + mLeftHPad(p.pad_left), + mRightHPad(p.pad_right), + mBottomVPad(p.pad_bottom), + mHoverGlowStrength(p.hover_glow_amount), + mCommitOnReturn(p.commit_on_return), + mCommitOnCaptureLost(p.commit_on_capture_lost), + mFadeWhenDisabled(false), + mForcePressedState(false), + mDisplayPressedState(p.display_pressed_state), + mLastDrawCharsCount(0), + mMouseDownSignal(NULL), + mMouseUpSignal(NULL), + mHeldDownSignal(NULL), + mUseDrawContextAlpha(p.use_draw_context_alpha), + mHandleRightMouse(p.handle_right_mouse), + mFlashingTimer(NULL) +{ + if (p.button_flash_enable) + { + // If optional parameter "p.button_flash_count" is not provided, LLFlashTimer will be + // used instead it a "default" value from gSavedSettings.getS32("FlashCount")). + // Likewise, missing "p.button_flash_rate" is replaced by gSavedSettings.getF32("FlashPeriod"). + // Note: flashing should be allowed in settings.xml (boolean key "EnableButtonFlashing"). + S32 flash_count = p.button_flash_count.isProvided()? p.button_flash_count : 0; + F32 flash_rate = p.button_flash_rate.isProvided()? p.button_flash_rate : 0.0; + mFlashingTimer = new LLFlashTimer ((LLFlashTimer::callback_t)NULL, flash_count, flash_rate); + } + else + { + mButtonFlashCount = p.button_flash_count; + mButtonFlashRate = p.button_flash_rate; + } + + static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0); + static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>()); + + if (!p.label_selected.isProvided()) + { + mSelectedLabel = mUnselectedLabel; + } + + // Hack to make sure there is space for at least one character + if (getRect().mRight >= 0 && getRect().getWidth() > 0 && + getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" "))) + { + // Use old defaults + mLeftHPad = llbutton_orig_h_pad; + mRightHPad = llbutton_orig_h_pad; + } + + mMouseDownTimer.stop(); + + // if custom unselected button image provided... + if (p.image_unselected != default_params.image_unselected) + { + //...fade it out for disabled image by default... + if (p.image_disabled() == default_params.image_disabled() ) + { + mImageDisabled = p.image_unselected; + mFadeWhenDisabled = true; + } + + if (p.image_pressed_selected == default_params.image_pressed_selected) + { + mImagePressedSelected = mImageUnselected; + } + } + + // if custom selected button image provided... + if (p.image_selected != default_params.image_selected) + { + //...fade it out for disabled image by default... + if (p.image_disabled_selected() == default_params.image_disabled_selected()) + { + mImageDisabledSelected = p.image_selected; + mFadeWhenDisabled = true; + } + + if (p.image_pressed == default_params.image_pressed) + { + mImagePressed = mImageSelected; + } + } + + if (!p.image_pressed.isProvided()) + { + mImagePressed = mImageSelected; + } + + if (!p.image_pressed_selected.isProvided()) + { + mImagePressedSelected = mImageUnselected; + } + + if (mImageUnselected.isNull()) + { + LL_WARNS() << "Button: " << getName() << " with no image!" << LL_ENDL; + } + + if (p.click_callback.isProvided()) + { + setCommitCallback(initCommitCallback(p.click_callback)); // alias -> commit_callback + } + if (p.mouse_down_callback.isProvided()) + { + setMouseDownCallback(initCommitCallback(p.mouse_down_callback)); + } + if (p.mouse_up_callback.isProvided()) + { + setMouseUpCallback(initCommitCallback(p.mouse_up_callback)); + } + if (p.mouse_held_callback.isProvided()) + { + setHeldDownCallback(initCommitCallback(p.mouse_held_callback)); + } + + if (p.badge.isProvided()) + { + LLBadgeOwner::initBadgeParams(p.badge()); + } +} + +LLButton::~LLButton() +{ + delete mMouseDownSignal; + delete mMouseUpSignal; + delete mHeldDownSignal; + + if (mFlashingTimer) + { + mFlashingTimer->unset(); + } +} + +// HACK: Committing a button is the same as instantly clicking it. +// virtual +void LLButton::onCommit() +{ + // WARNING: Sometimes clicking a button destroys the floater or + // panel containing it. Therefore we need to call LLUICtrl::onCommit() + // LAST, otherwise this becomes deleted memory. + + if (mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); + + if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); + + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } + + if (getSoundFlags() & MOUSE_UP) + { + make_ui_sound("UISndClickRelease"); + } + + if (mIsToggle) + { + toggleState(); + } + + // do this last, as it can result in destroying this button + LLUICtrl::onCommit(); +} + +boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) +{ + return setClickedCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setMouseDownCallback(const CommitCallbackParam& cb) +{ + return setMouseDownCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setMouseUpCallback(const CommitCallbackParam& cb) +{ + return setMouseUpCallback(initCommitCallback(cb)); +} +boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackParam& cb) +{ + return setHeldDownCallback(initCommitCallback(cb)); +} + + +boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mCommitSignal) mCommitSignal = new commit_signal_t(); + return mCommitSignal->connect(cb); +} +boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t(); + return mMouseDownSignal->connect(cb); +} +boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t(); + return mMouseUpSignal->connect(cb); +} +boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb ) +{ + if (!mHeldDownSignal) mHeldDownSignal = new commit_signal_t(); + return mHeldDownSignal->connect(cb); +} + + +// *TODO: Deprecate (for backwards compatibility only) +boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data ) +{ + return setClickedCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data ) +{ + return setMouseDownCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data ) +{ + return setMouseUpCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data ) +{ + return setHeldDownCallback(boost::bind(cb, data)); +} + +bool LLButton::postBuild() +{ + autoResize(); + + addBadgeToParentHolder(); + + return LLUICtrl::postBuild(); +} + +bool LLButton::handleUnicodeCharHere(llwchar uni_char) +{ + bool handled = false; + if(' ' == uni_char + && !gKeyboard->getKeyRepeated(' ')) + { + if (mIsToggle) + { + toggleState(); + } + + LLUICtrl::onCommit(); + + handled = true; + } + return handled; +} + +bool LLButton::handleKeyHere(KEY key, MASK mask ) +{ + bool handled = false; + if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key)) + { + if (mIsToggle) + { + toggleState(); + } + + handled = true; + + LLUICtrl::onCommit(); + } + return handled; +} + + +bool LLButton::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (!childrenHandleMouseDown(x, y, mask)) + { + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); + + if (hasTabStop() && !getIsChrome()) + { + setFocus(true); + } + + if (!mFunctionName.empty()) + { + LL_DEBUGS("UIUsage") << "calling mouse down function " << mFunctionName << LL_ENDL; + LLUIUsage::instance().logCommand(mFunctionName); + LLUIUsage::instance().logControl(getPathname()); + } + + /* + * ATTENTION! This call fires another mouse down callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseDownSignal(x, y, mask); + */ + LLUICtrl::handleMouseDown(x, y, mask); + + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); + + if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); + + mMouseDownTimer.start(); + mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); + mMouseHeldDownCount = 0; + + + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } + } + return true; +} + + +bool LLButton::handleMouseUp(S32 x, S32 y, MASK mask) +{ + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { + // reset timers before focus change, to not cause + // additional commits if mCommitOnCaptureLost. + resetMouseDownTimer(); + + // Always release the mouse + gFocusMgr.setMouseCapture( NULL ); + + /* + * ATTENTION! This call fires another mouse up callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseUpSignal(x, y, mask); + */ + LLUICtrl::handleMouseUp(x, y, mask); + LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname()); + + // Regardless of where mouseup occurs, handle callback + if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); + + // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. + // If mouseup in the widget, it's been clicked + if (pointInView(x, y)) + { + if (getSoundFlags() & MOUSE_UP) + { + make_ui_sound("UISndClickRelease"); + } + + if (mIsToggle) + { + toggleState(); + } + + LLUICtrl::onCommit(); + } + } + else + { + childrenHandleMouseUp(x, y, mask); + } + + return true; +} + +bool LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mHandleRightMouse && !childrenHandleRightMouseDown(x, y, mask)) + { + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); + + if (hasTabStop() && !getIsChrome()) + { + setFocus(true); + } + +// if (pointInView(x, y)) +// { +// } + // send the mouse down signal + LLUICtrl::handleRightMouseDown(x,y,mask); + // *TODO: Return result of LLUICtrl call above? Should defer to base class + // but this might change the mouse handling of existing buttons in a bad way + // if they are not mouse opaque. + } + + return true; +} + +bool LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask) +{ + if (mHandleRightMouse) + { + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { + // Always release the mouse + gFocusMgr.setMouseCapture( NULL ); + + // if (pointInView(x, y)) + // { + // mRightMouseUpSignal(this, x,y,mask); + // } + } + else + { + childrenHandleRightMouseUp(x, y, mask); + } + + // send the mouse up signal + LLUICtrl::handleRightMouseUp(x,y,mask); + // *TODO: Return result of LLUICtrl call above? Should defer to base class + // but this might change the mouse handling of existing buttons in a bad way. + // if they are not mouse opaque. + } + return true; +} + +void LLButton::onMouseLeave(S32 x, S32 y, MASK mask) +{ + LLUICtrl::onMouseLeave(x, y, mask); + + mNeedsHighlight = false; +} + +void LLButton::setHighlight(bool b) +{ + mNeedsHighlight = b; +} + +bool LLButton::handleHover(S32 x, S32 y, MASK mask) +{ + if (isInEnabledChain() + && (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this)) + mNeedsHighlight = true; + + if (!childrenHandleHover(x, y, mask)) + { + if (mMouseDownTimer.getStarted()) + { + F32 elapsed = getHeldDownTime(); + if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) + { + LLSD param; + param["count"] = mMouseHeldDownCount++; + if (mHeldDownSignal) (*mHeldDownSignal)(this, param); + } + } + + // We only handle the click if the click both started and ended within us + getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL; + } + return true; +} + +void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height) +{ + overlay_width = mImageOverlay->getWidth(); + overlay_height = mImageOverlay->getHeight(); + + F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f); + overlay_width = ll_round((F32)overlay_width * scale_factor); + overlay_height = ll_round((F32)overlay_height * scale_factor); +} + + +// virtual +void LLButton::draw() +{ + static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::getInstance()->mSettingGroups["config"], "EnableButtonFlashing", true); + F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency(); + + bool pressed_by_keyboard = false; + if (hasFocus()) + { + pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN)); + } + + bool mouse_pressed_and_over = false; + if (hasMouseCapture()) + { + S32 local_mouse_x ; + S32 local_mouse_y; + LLUI::getInstance()->getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); + mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y); + } + + bool enabled = isInEnabledChain(); + + bool pressed = pressed_by_keyboard + || mouse_pressed_and_over + || mForcePressedState; + bool selected = getToggleState(); + + bool use_glow_effect = false; + LLColor4 highlighting_color = LLColor4::white; + LLColor4 glow_color = LLColor4::white; + LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA; + LLUIImage* imagep = NULL; + LLUIImage* image_glow = NULL; + + // Cancel sticking of color, if the button is pressed, + // or when a flashing of the previously selected button is ended + if (mFlashingTimer + && ((selected && !mFlashingTimer->isFlashingInProgress() && !mForceFlashing) || pressed)) + { + mFlashing = false; + } + + bool flash = mFlashing && sEnableButtonFlashing; + + if (pressed && mDisplayPressedState) + { + imagep = selected ? mImagePressedSelected : mImagePressed; + } + else if ( mNeedsHighlight ) + { + if (selected) + { + if (mImageHoverSelected) + { + imagep = mImageHoverSelected; + } + else + { + imagep = mImageSelected; + use_glow_effect = true; + } + } + else + { + if (mImageHoverUnselected) + { + imagep = mImageHoverUnselected; + } + else + { + imagep = mImageUnselected; + use_glow_effect = true; + } + } + } + else + { + imagep = selected ? mImageSelected : mImageUnselected; + } + + // Override if more data is available + // HACK: Use gray checked state to mean either: + // enabled and tentative + // or + // disabled but checked + if (!mImageDisabledSelected.isNull() + && + ( (enabled && getTentative()) + || (!enabled && selected ) ) ) + { + imagep = mImageDisabledSelected; + } + else if (!mImageDisabled.isNull() + && !enabled + && !selected) + { + imagep = mImageDisabled; + } + + image_glow = imagep; + + if (mFlashing) + { + if (flash && mImageFlash) + { + // if button should flash and we have icon for flashing, use it as image for button + image_glow = mImageFlash; + } + + // provide fade-in and fade-out via flash_color + if (mFlashingTimer) + { + LLColor4 flash_color = mFlashBgColor.get(); + use_glow_effect = true; + glow_type = LLRender::BT_ALPHA; // blend the glow + + if (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress()) + { + glow_color = flash_color; + } + else if (mNeedsHighlight) + { + glow_color = highlighting_color; + } + else + { + // will fade from highlight color + glow_color = flash_color; + } + } + } + + if (mNeedsHighlight && !imagep) + { + use_glow_effect = true; + } + + // Figure out appropriate color for the text + LLColor4 label_color; + + // label changes when button state changes, not when pressed + if ( enabled ) + { + if ( getToggleState() ) + { + label_color = mSelectedLabelColor.get(); + } + else + { + label_color = mUnselectedLabelColor.get(); + } + } + else + { + if ( getToggleState() ) + { + label_color = mDisabledSelectedLabelColor.get(); + } + else + { + label_color = mDisabledLabelColor.get(); + } + } + + // Highlight if needed + if( ll::ui::SearchableControl::getHighlighted() ) + label_color = ll::ui::SearchableControl::getHighlightColor(); + + // Unselected label assignments + LLWString label = getCurrentLabel(); + + // overlay with keyboard focus border + if (hasFocus()) + { + F32 lerp_amt = gFocusMgr.getFocusFlashAmt(); + drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, ll_round(lerp(1.f, 3.f, lerp_amt))); + } + + if (use_glow_effect) + { + mCurGlowStrength = lerp(mCurGlowStrength, + mFlashing ? (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress() || mNeedsHighlight? 1.f : 0.f) : mHoverGlowStrength, + LLSmoothInterpolation::getInterpolant(0.05f)); + } + else + { + mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f)); + } + + // Draw button image, if available. + // Otherwise draw basic rectangular button. + if (imagep != NULL) + { + // apply automatic 50% alpha fade to disabled image + LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get(); + if ( mScaleImage) + { + imagep->draw(getLocalRect(), (enabled ? mImageColor.get() : disabled_color) % alpha ); + if (mCurGlowStrength > 0.01f) + { + gGL.setSceneBlendType(glow_type); + image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha)); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + else + { + S32 y = getLocalRect().getHeight() - imagep->getHeight(); + imagep->draw(0, y, (enabled ? mImageColor.get() : disabled_color) % alpha); + if (mCurGlowStrength > 0.01f) + { + gGL.setSceneBlendType(glow_type); + image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha)); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + } + else + { + // no image + LL_DEBUGS() << "No image for button " << getName() << LL_ENDL; + // draw it in pink so we can find it + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1 % alpha, false); + } + + // let overlay image and text play well together + S32 text_left = mLeftHPad; + S32 text_right = getRect().getWidth() - mRightHPad; + S32 text_width = getRect().getWidth() - mLeftHPad - mRightHPad; + + // draw overlay image + if (mImageOverlay.notNull()) + { + // get max width and height (discard level 0) + S32 overlay_width; + S32 overlay_height; + + getOverlayImageSize(overlay_width, overlay_height); + + S32 center_x = getLocalRect().getCenterX(); + S32 center_y = getLocalRect().getCenterY(); + + //FUGLY HACK FOR "DEPRESSED" BUTTONS + if (pressed && mDisplayPressedState) + { + center_y--; + center_x++; + } + + center_y += (mImageOverlayBottomPad - mImageOverlayTopPad); + // fade out overlay images on disabled buttons + LLColor4 overlay_color = mImageOverlayColor.get(); + if (!enabled) + { + overlay_color = mImageOverlayDisabledColor.get(); + } + else if (getToggleState()) + { + overlay_color = mImageOverlaySelectedColor.get(); + } + overlay_color.mV[VALPHA] *= alpha; + + switch(mImageOverlayAlignment) + { + case LLFontGL::LEFT: + text_left += overlay_width + mImgOverlayLabelSpace; + text_width -= overlay_width + mImgOverlayLabelSpace; + mImageOverlay->draw( + mLeftHPad, + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + overlay_color); + break; + case LLFontGL::HCENTER: + mImageOverlay->draw( + center_x - (overlay_width / 2), + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + overlay_color); + break; + case LLFontGL::RIGHT: + text_right -= overlay_width + mImgOverlayLabelSpace; + text_width -= overlay_width + mImgOverlayLabelSpace; + mImageOverlay->draw( + getRect().getWidth() - mRightHPad - overlay_width, + center_y - (overlay_height / 2), + overlay_width, + overlay_height, + overlay_color); + break; + default: + // draw nothing + break; + } + } + + // Draw label + if( !label.empty() ) + { + LLWStringUtil::trim(label); + + S32 x; + switch( mHAlign ) + { + case LLFontGL::RIGHT: + x = text_right; + break; + case LLFontGL::HCENTER: + x = text_left + (text_width / 2); + break; + case LLFontGL::LEFT: + default: + x = text_left; + break; + } + + if (pressed && mDisplayPressedState) + { + x++; + } + + // *NOTE: mantipov: before mUseEllipses is implemented in EXT-279 U32_MAX has been passed as + // max_chars. + // LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value. + // Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode. + // Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars. + mLastDrawCharsCount = mGLFont->render(label, 0, + (F32)x, + (F32)(getRect().getHeight() / 2 + mBottomVPad), + label_color % alpha, + mHAlign, LLFontGL::VCENTER, + LLFontGL::NORMAL, + mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW, + S32_MAX, text_width, + NULL, mUseEllipses, mUseFontColor); + } + + LLUICtrl::draw(); +} + +void LLButton::drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size) +{ + if (imagep == NULL) return; + if (mScaleImage) + { + imagep->drawBorder(getLocalRect(), color, size); + } + else + { + S32 y = getLocalRect().getHeight() - imagep->getHeight(); + imagep->drawBorder(0, y, color, size); + } +} + +bool LLButton::getToggleState() const +{ + return getValue().asBoolean(); +} + +void LLButton::setToggleState(bool b) +{ + if( b != getToggleState() ) + { + setControlValue(b); // will fire LLControlVariable callbacks (if any) + setValue(b); // may or may not be redundant + setFlashing(false); // stop flash state whenever the selected/unselected state if reset + // Unselected label assignments + autoResize(); + } +} + +void LLButton::setFlashing(bool b, bool force_flashing/* = false */) +{ + mForceFlashing = force_flashing; + if (mFlashingTimer) + { + mFlashing = b; + (b ? mFlashingTimer->startFlashing() : mFlashingTimer->stopFlashing()); + } + else if (b != mFlashing) + { + mFlashing = b; + mFrameTimer.reset(); + } +} + +bool LLButton::toggleState() +{ + bool flipped = ! getToggleState(); + setToggleState(flipped); + + return flipped; +} + +void LLButton::setLabel( const std::string& label ) +{ + mUnselectedLabel = mSelectedLabel = label; +} + +void LLButton::setLabel( const LLUIString& label ) +{ + mUnselectedLabel = mSelectedLabel = label; +} + +void LLButton::setLabel( const LLStringExplicit& label ) +{ + setLabelUnselected(label); + setLabelSelected(label); +} + +//virtual +bool LLButton::setLabelArg( const std::string& key, const LLStringExplicit& text ) +{ + mUnselectedLabel.setArg(key, text); + mSelectedLabel.setArg(key, text); + return true; +} + +void LLButton::setLabelUnselected( const LLStringExplicit& label ) +{ + mUnselectedLabel = label; +} + +void LLButton::setLabelSelected( const LLStringExplicit& label ) +{ + mSelectedLabel = label; +} + +bool LLButton::labelIsTruncated() const +{ + return getCurrentLabel().getString().size() > mLastDrawCharsCount; +} + +const LLUIString& LLButton::getCurrentLabel() const +{ + return getToggleState() ? mSelectedLabel : mUnselectedLabel; +} + +void LLButton::setImageUnselected(LLPointer<LLUIImage> image) +{ + mImageUnselected = image; + if (mImageUnselected.isNull()) + { + LL_WARNS() << "Setting default button image for: " << getName() << " to NULL" << LL_ENDL; + } +} + +void LLButton::autoResize() +{ + resize(getCurrentLabel()); +} + +void LLButton::resize(LLUIString label) +{ + // get label length + S32 label_width = mGLFont->getWidth(label.getString()); + // get current btn length + S32 btn_width =getRect().getWidth(); + // check if it need resize + if (mAutoResize) + { + S32 min_width = label_width + mLeftHPad + mRightHPad; + if (mImageOverlay) + { + S32 overlay_width = mImageOverlay->getWidth(); + F32 scale_factor = (getRect().getHeight() - (mImageOverlayBottomPad + mImageOverlayTopPad)) / (F32)mImageOverlay->getHeight(); + overlay_width = ll_round((F32)overlay_width * scale_factor); + + switch(mImageOverlayAlignment) + { + case LLFontGL::LEFT: + case LLFontGL::RIGHT: + min_width += overlay_width + mImgOverlayLabelSpace; + break; + case LLFontGL::HCENTER: + min_width = llmax(min_width, overlay_width + mLeftHPad + mRightHPad); + break; + default: + // draw nothing + break; + } + } + if (btn_width < min_width) + { + reshape(min_width, getRect().getHeight()); + } + } +} +void LLButton::setImages( const std::string &image_name, const std::string &selected_name ) +{ + setImageUnselected(LLUI::getUIImage(image_name)); + setImageSelected(LLUI::getUIImage(selected_name)); +} + +void LLButton::setImageSelected(LLPointer<LLUIImage> image) +{ + mImageSelected = image; +} + +void LLButton::setImageColor(const LLColor4& c) +{ + mImageColor = c; +} + +void LLButton::setColor(const LLColor4& color) +{ + setImageColor(color); +} + +void LLButton::setImageDisabled(LLPointer<LLUIImage> image) +{ + mImageDisabled = image; + mDisabledImageColor = mImageColor; + mFadeWhenDisabled = true; +} + +void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image) +{ + mImageDisabledSelected = image; + mDisabledImageColor = mImageColor; + mFadeWhenDisabled = true; +} + +void LLButton::setImagePressed(LLPointer<LLUIImage> image) +{ + mImagePressed = image; +} + +void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image) +{ + mImageHoverSelected = image; +} + +void LLButton::setImageHoverUnselected(LLPointer<LLUIImage> image) +{ + mImageHoverUnselected = image; +} + +void LLButton::setImageFlash(LLPointer<LLUIImage> image) +{ + mImageFlash = image; +} + +void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment, const LLColor4& color) +{ + if (image_name.empty()) + { + mImageOverlay = NULL; + } + else + { + mImageOverlay = LLUI::getUIImage(image_name); + mImageOverlayAlignment = alignment; + mImageOverlayColor = color; + } +} + +void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment, const LLColor4& color) +{ + if (image_id.isNull()) + { + mImageOverlay = NULL; + } + else + { + mImageOverlay = LLUI::getUIImageByID(image_id); + mImageOverlayAlignment = alignment; + mImageOverlayColor = color; + } +} + +void LLButton::onMouseCaptureLost() +{ + if (mCommitOnCaptureLost + && mMouseDownTimer.getStarted()) + { + if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD()); + + if (mIsToggle) + { + toggleState(); + } + + LLUICtrl::onCommit(); + } + resetMouseDownTimer(); +} + +//------------------------------------------------------------------------- +// Utilities +//------------------------------------------------------------------------- +S32 round_up(S32 grid, S32 value) +{ + S32 mod = value % grid; + + if (mod > 0) + { + // not even multiple + return value + (grid - mod); + } + else + { + return value; + } +} + +void LLButton::addImageAttributeToXML(LLXMLNodePtr node, + const std::string& image_name, + const LLUUID& image_id, + const std::string& xml_tag_name) const +{ + if( !image_name.empty() ) + { + node->createChild(xml_tag_name.c_str(), true)->setStringValue(image_name); + } + else if( image_id != LLUUID::null ) + { + node->createChild((xml_tag_name + "_id").c_str(), true)->setUUIDValue(image_id); + } +} + + +// static +void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname) +{ + bool floater_vis = LLFloaterReg::toggleInstance(sdname.asString()); + LLButton* button = dynamic_cast<LLButton*>(ctrl); + if (button) + button->setToggleState(floater_vis); +} + +// static +// Gets called once +void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname) +{ + LLButton* button = dynamic_cast<LLButton*>(ctrl); + if (!button) + return; + // Get the visibility control name for the floater + std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); + // Set the button control value (toggle state) to the floater visibility control (Sets the value as well) + button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name)); + // Set the clicked callback to toggle the floater + button->setClickedCallback(boost::bind(&LLFloaterReg::toggleInstance, sdname, LLSD())); +} + +// static +void LLButton::setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname) +{ + LLButton* button = dynamic_cast<LLButton*>(ctrl); + if (!button) + return; + // Get the visibility control name for the floater + std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); + // Set the button control value (toggle state) to the floater visibility control (Sets the value as well) + button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name)); + // Set the clicked callback to toggle the floater + button->setClickedCallback(boost::bind(&LLDockableFloater::toggleInstance, sdname)); +} + +// static +void LLButton::showHelp(LLUICtrl* ctrl, const LLSD& sdname) +{ + // search back through the button's parents for a panel + // with a help_topic string defined + std::string help_topic; + if (LLUI::getInstance()->mHelpImpl && + ctrl->findHelpTopic(help_topic)) + { + LLUI::getInstance()->mHelpImpl->showTopic(help_topic); + return; // success + } + + // display an error if we can't find a help_topic string. + // fix this by adding a help_topic attribute to the xui file + LLNotificationsUtil::add("UnableToFindHelpTopic"); +} + +void LLButton::resetMouseDownTimer() +{ + mMouseDownTimer.stop(); + mMouseDownTimer.reset(); +} + +bool LLButton::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + // just treat a double click as a second click + return handleMouseDown(x, y, mask); +} |