Newer
Older
/**
* @file llbutton.cpp
* @brief LLButton base class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* 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
#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 "llnotificationsutil.h"
#include "llrender.h"
#include "lluictrlfactory.h"
#include "llviewereventrecorder.h"
James Cook
committed
static LLDefaultChildRegistry::Register<LLButton> r("button");
// Compiler optimization, generate extern template
template class LLButton* LLView::getChild<class LLButton>(

Rye Mutt
committed
std::string_view name, BOOL recurse) const;
S32 LLBUTTON_H_PAD = 4;
LLButton::Params::Params()
: label_selected("label_selected"), // requires is_toggle true
James Cook
committed
label_shadow("label_shadow", true),
auto_resize("auto_resize", false),
use_ellipses("use_ellipses", false),
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_overlay_enable("image_overlay_enable", true),
Paul Guslisty
committed
image_top_pad("image_top_pad"),
image_bottom_pad("image_bottom_pad"),
Paul Guslisty
committed
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),
Leslie Linden
committed
display_pressed_state("display_pressed_state", true),
use_draw_context_alpha("use_draw_context_alpha", true),
handle_right_mouse("handle_right_mouse"),
Leslie Linden
committed
held_down_delay("held_down_delay"),
button_flash_enable("button_flash_enable", false),
Leslie Linden
committed
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),
Richard Linden
committed
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),
mImageOverlayEnable(p.image_overlay_enable),
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)),
Paul Guslisty
committed
mImageOverlayTopPad(p.image_top_pad),
mImageOverlayBottomPad(p.image_bottom_pad),
Paul Guslisty
committed
mImgOverlayLabelSpace(p.imgoverlay_label_space),
mIsToggle(p.is_toggle),
mScaleImage(p.scale_image),
James Cook
committed
mDropShadowedText(p.label_shadow),
mAutoResize(p.auto_resize),
mUseEllipses( p.use_ellipses ),
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),
James Cook
committed
mFadeWhenDisabled(FALSE),
Leslie Linden
committed
mDisplayPressedState(p.display_pressed_state),
mLastDrawCharsCount(0),
mMouseDownSignal(NULL),
mMouseUpSignal(NULL),
mHeldDownSignal(NULL),
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;
}
AlexanderP ProductEngine
committed
static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
James Cook
committed
static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>());
AlexanderP ProductEngine
committed
if (!p.label_selected.isProvided())
mSelectedLabel = mUnselectedLabel;
}
// Hack to make sure there is space for at least one character
if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
mLeftHPad = llbutton_orig_h_pad;
mRightHPad = llbutton_orig_h_pad;
// 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));
}
LLBadgeOwner::initBadgeParams(p.badge());
}
LLButton::~LLButton()
{
delete mMouseDownSignal;
delete mMouseUpSignal;
delete mHeldDownSignal;
if (mFlashingTimer)
{
AlexanderP ProductEngine
committed
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()
if (mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
Steven Bennetts
committed
if (getSoundFlags() & MOUSE_DOWN)
Steven Bennetts
committed
if (getSoundFlags() & MOUSE_UP)
AlexanderP ProductEngine
committed
if (mIsToggle)
{
toggleState();
}
// do this last, as it can result in destroying this button
LLUICtrl::onCommit();
}
Leslie Linden
committed
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));
}
Nat Goodspeed
committed
boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )
if (!mCommitSignal) mCommitSignal = new commit_signal_t();
return mCommitSignal->connect(cb);
Nat Goodspeed
committed
boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb )
if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
return mMouseDownSignal->connect(cb);
Nat Goodspeed
committed
boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb )
if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t();
return mMouseUpSignal->connect(cb);
Nat Goodspeed
committed
boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb )
if (!mHeldDownSignal) mHeldDownSignal = new commit_signal_t();
return mHeldDownSignal->connect(cb);
Richard Linden
committed
// *TODO: Deprecate (for backwards compatibility only)
Nat Goodspeed
committed
boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
{
return setClickedCallback(boost::bind(cb, data));
}
Nat Goodspeed
committed
boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data )
{
return setMouseDownCallback(boost::bind(cb, data));
}
Nat Goodspeed
committed
boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data )
{
return setMouseUpCallback(boost::bind(cb, data));
}
Nat Goodspeed
committed
boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data )
{
return setHeldDownCallback(boost::bind(cb, data));
}
BOOL LLButton::postBuild()
{
autoResize();
Stinson Linden
committed
addBadgeToParentHolder();
return LLUICtrl::postBuild();
BOOL LLButton::handleUnicodeCharHere(llwchar uni_char)
if(' ' == uni_char
&& !gKeyboard->getKeyRepeated(' '))
if (mIsToggle)
{
toggleState();
}
LLUICtrl::onCommit();
BOOL LLButton::handleKeyHere(KEY key, MASK mask )
if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
toggleState();
}
LLUICtrl::onCommit();
}
return handled;
}
BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
{
James Cook
committed
if (!childrenHandleMouseDown(x, y, mask))
James Cook
committed
// Route future Mouse messages here preemptively. (Release on mouse up.)
gFocusMgr.setMouseCapture( this );
James Cook
committed
if (hasTabStop() && !getIsChrome())
{
setFocus(TRUE);
}
if (!mFunctionName.empty())
{
LL_DEBUGS("UIUsage") << "calling mouse down function " << mFunctionName << LL_ENDL;
}
/*
* 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);
#if AL_VIEWER_EVENT_RECORDER
if(LLViewerEventRecorder::getLoggingStatus())
{
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
}
#endif
if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD());
James Cook
committed
mMouseDownTimer.start();
mMouseDownFrame = (S32) LLFrameTimer::getFrameCount();
mMouseHeldDownCount = 0;
James Cook
committed
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
Josh Bell
committed
if( hasMouseCapture() )
Josh Bell
committed
// 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);
#if AL_VIEWER_EVENT_RECORDER
if (LLViewerEventRecorder::getLoggingStatus())
{
LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
}
#endif
// Regardless of where mouseup occurs, handle callback
if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
resetMouseDownTimer();
// 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))
{
Steven Bennetts
committed
if (getSoundFlags() & MOUSE_UP)
if (mIsToggle)
{
toggleState();
}
LLUICtrl::onCommit();
James Cook
committed
else
{
childrenHandleMouseUp(x, y, mask);
}
BOOL LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
if (mHandleRightMouse && !childrenHandleRightMouseDown(x, y, mask))
James Cook
committed
// Route future Mouse messages here preemptively. (Release on mouse up.)
gFocusMgr.setMouseCapture( this );
James Cook
committed
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)
// 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.
James Cook
committed
}
return TRUE;
}
void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
{
mNeedsHighlight = FALSE;
}
void LLButton::setHighlight(bool b)
{
mNeedsHighlight = b;
}
BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
{
&& (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this))
mNeedsHighlight = TRUE;
James Cook
committed
if (!childrenHandleHover(x, y, mask))
James Cook
committed
if (mMouseDownTimer.getStarted())
James Cook
committed
F32 elapsed = getHeldDownTime();
if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame)
{
LLSD param;
param["count"] = mMouseHeldDownCount++;
if (mHeldDownSignal) (*mHeldDownSignal)(this, param);
James Cook
committed
}
James Cook
committed
// We only handle the click if the click both started and ended within us
getWindow()->setCursor(UI_CURSOR_ARROW);
#ifdef SHOW_DEBUG
LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL;
James Cook
committed
}
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);
callum_linden
committed
overlay_width = ll_round((F32)overlay_width * scale_factor);
overlay_height = ll_round((F32)overlay_height * scale_factor);
static const LLUICachedControl<bool> sEnableButtonFlashing("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));
}
Richard Linden
committed
bool mouse_pressed_and_over = false;
if (hasMouseCapture())
{
S32 local_mouse_x ;
S32 local_mouse_y;

Rye Mutt
committed
LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
Richard Linden
committed
mouse_pressed_and_over = pointInView(local_mouse_x, local_mouse_y);
}
bool enabled = isInEnabledChain();
bool pressed = pressed_by_keyboard
Richard Linden
committed
|| mouse_pressed_and_over
James Cook
committed
|| mForcePressedState;
bool selected = getToggleState();
bool use_glow_effect = FALSE;
AlexanderP ProductEngine
committed
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;
AlexanderP ProductEngine
committed
// Cancel sticking of color, if the button is pressed,
// or when a flashing of the previously selected button is ended
if (mFlashingTimer
Mnikolenko ProductEngine
committed
&& ((selected && !mFlashingTimer->isFlashingInProgress() && !mForceFlashing) || pressed))
AlexanderP ProductEngine
committed
{
mFlashing = false;
}
bool flash = mFlashing && sEnableButtonFlashing;
Leslie Linden
committed
if (pressed && mDisplayPressedState)
imagep = selected ? mImagePressedSelected : mImagePressed;
}
else if ( mNeedsHighlight )
{
if (selected)
if (mImageHoverSelected)
imagep = mImageHoverSelected;
imagep = mImageSelected;
use_glow_effect = TRUE;
if (mImageHoverUnselected)
imagep = mImageHoverUnselected;
imagep = mImageUnselected;
use_glow_effect = TRUE;
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;
AlexanderP ProductEngine
committed
if (mFlashing)
{
// 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
AlexanderP ProductEngine
committed
if (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress())
AlexanderP ProductEngine
committed
{
glow_color = flash_color;
AlexanderP ProductEngine
committed
}
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();
label_color = mUnselectedLabelColor.get();
}
else
{
if ( getToggleState() )
label_color = mDisabledSelectedLabelColor.get();
label_color = mDisabledLabelColor.get();
// Highlight if needed
if( ll::ui::SearchableControl::getHighlighted() )
label_color = ll::ui::SearchableControl::getHighlightColor();
// Unselected label assignments
Richard Nelson
committed
LLWString label = getCurrentLabel();
// overlay with keyboard focus border
if (hasFocus())
{
F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
callum_linden
committed
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)
Richard Nelson
committed
imagep->draw(getLocalRect(), (enabled ? mImageColor.get() : disabled_color) % alpha );
gGL.setSceneBlendType(glow_type);
image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
gGL.setSceneBlendType(LLRender::BT_ALPHA);
S32 y = getLocalRect().getHeight() - imagep->getHeight();
imagep->draw(0, y, (enabled ? mImageColor.get() : disabled_color) % alpha);
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
Richard Nelson
committed
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 (mImageOverlayEnable && 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
Leslie Linden
committed
if (pressed && mDisplayPressedState)
{
center_y--;
center_x++;
}
Paul Guslisty
committed
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())
Leslie Linden
committed
{
overlay_color = mImageOverlaySelectedColor.get();
Leslie Linden
committed
}
Richard Nelson
committed
overlay_color.mV[VALPHA] *= alpha;
switch(mImageOverlayAlignment)
{
case LLFontGL::LEFT:
Paul Guslisty
committed
text_left += overlay_width + mImgOverlayLabelSpace;
text_width -= overlay_width + mImgOverlayLabelSpace;
mImageOverlay->draw(
Paul Guslisty
committed
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:
Paul Guslisty
committed
text_right -= overlay_width + mImgOverlayLabelSpace;
text_width -= overlay_width + mImgOverlayLabelSpace;
mImageOverlay->draw(
Paul Guslisty
committed
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:
Richard Linden
committed
x = text_left + (text_width / 2);
break;
case LLFontGL::LEFT:
default:
x = text_left;
break;
S32 y_offset = 2 + (getRect().getHeight() - 20)/2;
Leslie Linden
committed
if (pressed && mDisplayPressedState)
y_offset--;
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,
Richard Linden
committed
(F32)(getRect().getHeight() / 2 + mBottomVPad),
Richard Nelson
committed
label_color % alpha,
Richard Linden
committed
mHAlign, LLFontGL::VCENTER,
LLFontGL::NORMAL,
mDropShadowedText ? LLFontGL::DROP_SHADOW : LLFontGL::NO_SHADOW,
S32_MAX, text_width,
NULL, mUseEllipses);
LLUICtrl::draw();
void LLButton::drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size)
if (imagep == NULL) return;
imagep->drawBorder(getLocalRect(), color, size);
S32 y = getLocalRect().getHeight() - imagep->getHeight();
imagep->drawBorder(0, y, color, size);
BOOL LLButton::getToggleState() const
return getValue().asBoolean();
}
void LLButton::setToggleState(BOOL b)
{