1121 lines
28 KiB
C++
1121 lines
28 KiB
C++
/**
|
|
* @file llbutton.cpp
|
|
* @brief LLButton base class
|
|
*
|
|
* Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
|
|
* $License$
|
|
*/
|
|
|
|
#include "linden_common.h"
|
|
|
|
#include "llbutton.h"
|
|
|
|
// Linden library includes
|
|
#include "v4color.h"
|
|
#include "llstring.h"
|
|
|
|
// Project includes
|
|
#include "llkeyboard.h"
|
|
#include "llgl.h"
|
|
#include "llui.h"
|
|
#include "lluiconstants.h"
|
|
//#include "llcallbacklist.h"
|
|
#include "llresmgr.h"
|
|
#include "llcriticaldamp.h"
|
|
#include "llglheaders.h"
|
|
#include "llfocusmgr.h"
|
|
#include "llwindow.h"
|
|
|
|
// globals loaded from settings.xml
|
|
S32 LLBUTTON_ORIG_H_PAD = 6; // Pre-zoomable UI
|
|
S32 LLBUTTON_H_PAD = 0;
|
|
S32 LLBUTTON_V_PAD = 0;
|
|
S32 BTN_HEIGHT_SMALL= 0;
|
|
S32 BTN_HEIGHT = 0;
|
|
|
|
S32 BTN_GRID = 12;
|
|
S32 BORDER_SIZE = 1;
|
|
|
|
// static
|
|
LLFrameTimer LLButton::sFlashingTimer;
|
|
|
|
LLButton::LLButton( const LLString& name, const LLRect& rect, const LLString& control_name, void (*click_callback)(void*), void *callback_data)
|
|
: LLUICtrl(name, rect, TRUE, NULL, NULL),
|
|
mClickedCallback( click_callback ),
|
|
mMouseDownCallback( NULL ),
|
|
mMouseUpCallback( NULL ),
|
|
mHeldDownCallback( NULL ),
|
|
mGLFont( NULL ),
|
|
mMouseDownFrame( 0 ),
|
|
mHeldDownDelay( 0.5f ), // seconds until held-down callback is called
|
|
mHeldDownFrameDelay( 0 ),
|
|
mImageUnselected( NULL ),
|
|
mImageSelected( NULL ),
|
|
mImageHoverSelected( NULL ),
|
|
mImageHoverUnselected( NULL ),
|
|
mImageDisabled( NULL ),
|
|
mImageDisabledSelected( NULL ),
|
|
mToggleState( FALSE ),
|
|
mScaleImage( TRUE ),
|
|
mDropShadowedText( TRUE ),
|
|
mBorderEnabled( FALSE ),
|
|
mFlashing( FALSE ),
|
|
mHAlign( LLFontGL::HCENTER ),
|
|
mLeftHPad( LLBUTTON_H_PAD ),
|
|
mRightHPad( LLBUTTON_H_PAD ),
|
|
mFixedWidth( 16 ),
|
|
mFixedHeight( 16 ),
|
|
mHoverGlowStrength(0.15f),
|
|
mCurGlowStrength(0.f),
|
|
mNeedsHighlight(FALSE),
|
|
mCommitOnReturn(TRUE),
|
|
mImagep( NULL )
|
|
{
|
|
mUnselectedLabel = name;
|
|
mSelectedLabel = name;
|
|
|
|
setImageUnselected("button_enabled_32x128.tga");
|
|
setImageSelected("button_enabled_selected_32x128.tga");
|
|
setImageDisabled("button_disabled_32x128.tga");
|
|
setImageDisabledSelected("button_disabled_32x128.tga");
|
|
|
|
mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" );
|
|
mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" );
|
|
|
|
init(click_callback, callback_data, NULL, control_name);
|
|
}
|
|
|
|
|
|
LLButton::LLButton(const LLString& name, const LLRect& rect,
|
|
const LLString &unselected_image_name,
|
|
const LLString &selected_image_name,
|
|
const LLString& control_name,
|
|
void (*click_callback)(void*),
|
|
void *callback_data,
|
|
const LLFontGL *font,
|
|
const LLString& unselected_label,
|
|
const LLString& selected_label )
|
|
: LLUICtrl(name, rect, TRUE, NULL, NULL),
|
|
mClickedCallback( click_callback ),
|
|
mMouseDownCallback( NULL ),
|
|
mMouseUpCallback( NULL ),
|
|
mHeldDownCallback( NULL ),
|
|
mGLFont( NULL ),
|
|
mMouseDownFrame( 0 ),
|
|
mHeldDownDelay( 0.5f ), // seconds until held-down callback is called
|
|
mHeldDownFrameDelay( 0 ),
|
|
mImageUnselected( NULL ),
|
|
mImageSelected( NULL ),
|
|
mImageHoverSelected( NULL ),
|
|
mImageHoverUnselected( NULL ),
|
|
mImageDisabled( NULL ),
|
|
mImageDisabledSelected( NULL ),
|
|
mToggleState( FALSE ),
|
|
mScaleImage( TRUE ),
|
|
mDropShadowedText( TRUE ),
|
|
mBorderEnabled( FALSE ),
|
|
mFlashing( FALSE ),
|
|
mHAlign( LLFontGL::HCENTER ),
|
|
mLeftHPad( LLBUTTON_H_PAD ),
|
|
mRightHPad( LLBUTTON_H_PAD ),
|
|
mFixedWidth( 16 ),
|
|
mFixedHeight( 16 ),
|
|
mHoverGlowStrength(0.25f),
|
|
mCurGlowStrength(0.f),
|
|
mNeedsHighlight(FALSE),
|
|
mCommitOnReturn(TRUE),
|
|
mImagep( NULL )
|
|
{
|
|
mUnselectedLabel = unselected_label;
|
|
mSelectedLabel = selected_label;
|
|
|
|
// by default, disabled color is same as enabled
|
|
mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" );
|
|
mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" );
|
|
|
|
if( unselected_image_name != "" )
|
|
{
|
|
setImageUnselected(unselected_image_name);
|
|
setImageDisabled(unselected_image_name);
|
|
|
|
mDisabledImageColor.mV[VALPHA] = 0.5f;
|
|
mImageDisabled = mImageUnselected;
|
|
mDisabledImageColor.mV[VALPHA] = 0.5f;
|
|
// user-specified image - don't use fixed borders unless requested
|
|
mFixedWidth = 0;
|
|
mFixedHeight = 0;
|
|
mScaleImage = FALSE;
|
|
}
|
|
else
|
|
{
|
|
setImageUnselected("button_enabled_32x128.tga");
|
|
setImageDisabled("button_disabled_32x128.tga");
|
|
}
|
|
|
|
if( selected_image_name != "" )
|
|
{
|
|
setImageSelected(selected_image_name);
|
|
setImageDisabledSelected(selected_image_name);
|
|
|
|
mDisabledImageColor.mV[VALPHA] = 0.5f;
|
|
// user-specified image - don't use fixed borders unless requested
|
|
mFixedWidth = 0;
|
|
mFixedHeight = 0;
|
|
mScaleImage = FALSE;
|
|
}
|
|
else
|
|
{
|
|
setImageSelected("button_enabled_selected_32x128.tga");
|
|
setImageDisabledSelected("button_disabled_32x128.tga");
|
|
}
|
|
|
|
init(click_callback, callback_data, font, control_name);
|
|
}
|
|
|
|
void LLButton::init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const LLString& control_name)
|
|
{
|
|
mGLFont = ( font ? font : LLFontGL::sSansSerif);
|
|
|
|
// Hack to make sure there is space for at least one character
|
|
if (mRect.getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(" "))
|
|
{
|
|
// Use old defaults
|
|
mLeftHPad = LLBUTTON_ORIG_H_PAD;
|
|
mRightHPad = LLBUTTON_ORIG_H_PAD;
|
|
}
|
|
|
|
mCallbackUserData = callback_data;
|
|
mMouseDownTimer.stop();
|
|
|
|
setControlName(control_name, NULL);
|
|
|
|
mUnselectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelColor" ) );
|
|
mSelectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelSelectedColor" ) );
|
|
mDisabledLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelDisabledColor" ) );
|
|
mDisabledSelectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelSelectedDisabledColor" ) );
|
|
mHighlightColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedFgColor" ) );
|
|
mUnselectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedBgColor" ) );
|
|
mSelectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonSelectedBgColor" ) );
|
|
}
|
|
|
|
LLButton::~LLButton()
|
|
{
|
|
if( hasMouseCapture() )
|
|
{
|
|
gFocusMgr.setMouseCapture( NULL );
|
|
}
|
|
}
|
|
|
|
// virtual
|
|
EWidgetType LLButton::getWidgetType() const
|
|
{
|
|
return WIDGET_TYPE_BUTTON;
|
|
}
|
|
|
|
// virtual
|
|
LLString LLButton::getWidgetTag() const
|
|
{
|
|
return LL_BUTTON_TAG;
|
|
}
|
|
|
|
// 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 mClickedCallback
|
|
// LAST, otherwise this becomes deleted memory.
|
|
LLUICtrl::onCommit();
|
|
|
|
if (mMouseDownCallback)
|
|
{
|
|
(*mMouseDownCallback)(mCallbackUserData);
|
|
}
|
|
|
|
if (mMouseUpCallback)
|
|
{
|
|
(*mMouseUpCallback)(mCallbackUserData);
|
|
}
|
|
|
|
if (mSoundFlags & MOUSE_DOWN)
|
|
{
|
|
make_ui_sound("UISndClick");
|
|
}
|
|
|
|
if (mSoundFlags & MOUSE_UP)
|
|
{
|
|
make_ui_sound("UISndClickRelease");
|
|
}
|
|
|
|
if (mClickedCallback)
|
|
{
|
|
(*mClickedCallback)( mCallbackUserData );
|
|
}
|
|
}
|
|
|
|
BOOL LLButton::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent)
|
|
{
|
|
BOOL handled = FALSE;
|
|
if( getVisible() && mEnabled && !called_from_parent && ' ' == uni_char && !gKeyboard->getKeyRepeated(' '))
|
|
{
|
|
if (mClickedCallback)
|
|
{
|
|
(*mClickedCallback)( mCallbackUserData );
|
|
}
|
|
handled = TRUE;
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
BOOL LLButton::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent )
|
|
{
|
|
BOOL handled = FALSE;
|
|
if( getVisible() && mEnabled && !called_from_parent )
|
|
{
|
|
if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
|
|
{
|
|
if (mClickedCallback)
|
|
{
|
|
(*mClickedCallback)( mCallbackUserData );
|
|
}
|
|
handled = TRUE;
|
|
}
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
|
|
BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
|
|
{
|
|
// Route future Mouse messages here preemptively. (Release on mouse up.)
|
|
gFocusMgr.setMouseCapture( this );
|
|
|
|
if (hasTabStop() && !getIsChrome())
|
|
{
|
|
setFocus(TRUE);
|
|
}
|
|
|
|
if (mMouseDownCallback)
|
|
{
|
|
(*mMouseDownCallback)(mCallbackUserData);
|
|
}
|
|
|
|
mMouseDownTimer.start();
|
|
mMouseDownFrame = LLFrameTimer::getFrameCount();
|
|
|
|
if (mSoundFlags & 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() )
|
|
{
|
|
// Always release the mouse
|
|
gFocusMgr.setMouseCapture( NULL );
|
|
|
|
// Regardless of where mouseup occurs, handle callback
|
|
if (mMouseUpCallback)
|
|
{
|
|
(*mMouseUpCallback)(mCallbackUserData);
|
|
}
|
|
|
|
// 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 (mSoundFlags & MOUSE_UP)
|
|
{
|
|
make_ui_sound("UISndClickRelease");
|
|
}
|
|
|
|
if (mClickedCallback)
|
|
{
|
|
(*mClickedCallback)( mCallbackUserData );
|
|
}
|
|
}
|
|
|
|
mMouseDownTimer.stop();
|
|
mMouseDownTimer.reset();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
|
|
{
|
|
BOOL handled = FALSE;
|
|
|
|
LLMouseHandler* other_captor = gFocusMgr.getMouseCapture();
|
|
mNeedsHighlight = other_captor == NULL ||
|
|
other_captor == this ||
|
|
// this following bit is to support modal dialogs
|
|
(other_captor->isView() && hasAncestor((LLView*)other_captor));
|
|
|
|
if (mMouseDownTimer.getStarted() && NULL != mHeldDownCallback)
|
|
{
|
|
F32 elapsed = mMouseDownTimer.getElapsedTimeF32();
|
|
if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= LLFrameTimer::getFrameCount() - mMouseDownFrame)
|
|
{
|
|
mHeldDownCallback( mCallbackUserData );
|
|
}
|
|
}
|
|
|
|
// We only handle the click if the click both started and ended within us
|
|
if( hasMouseCapture() )
|
|
{
|
|
handled = TRUE;
|
|
}
|
|
else if( getVisible() )
|
|
{
|
|
// Opaque
|
|
handled = TRUE;
|
|
}
|
|
|
|
if( handled )
|
|
{
|
|
getWindow()->setCursor(UI_CURSOR_ARROW);
|
|
lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
|
|
// virtual
|
|
void LLButton::draw()
|
|
{
|
|
if( getVisible() )
|
|
{
|
|
BOOL flash = FALSE;
|
|
if( mFlashing )
|
|
{
|
|
F32 elapsed = LLButton::sFlashingTimer.getElapsedTimeF32();
|
|
flash = S32(elapsed * 2) & 1;
|
|
}
|
|
|
|
BOOL pressed_by_keyboard = FALSE;
|
|
if (hasFocus())
|
|
{
|
|
pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN));
|
|
}
|
|
|
|
// Unselected image assignments
|
|
S32 local_mouse_x;
|
|
S32 local_mouse_y;
|
|
LLCoordWindow cursor_pos_window;
|
|
getWindow()->getCursorPosition(&cursor_pos_window);
|
|
LLCoordGL cursor_pos_gl;
|
|
getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
|
|
cursor_pos_gl.mX = llround((F32)cursor_pos_gl.mX / LLUI::sGLScaleFactor.mV[VX]);
|
|
cursor_pos_gl.mY = llround((F32)cursor_pos_gl.mY / LLUI::sGLScaleFactor.mV[VY]);
|
|
screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &local_mouse_x, &local_mouse_y);
|
|
|
|
BOOL pressed = pressed_by_keyboard || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y));
|
|
|
|
BOOL display_state = FALSE;
|
|
if( pressed )
|
|
{
|
|
mImagep = mImageSelected;
|
|
// show the resulting state after releasing the mouse button while it is down
|
|
display_state = mToggleState ? FALSE : TRUE;
|
|
}
|
|
else
|
|
{
|
|
display_state = mToggleState || flash;
|
|
}
|
|
|
|
BOOL use_glow_effect = FALSE;
|
|
if ( mNeedsHighlight )
|
|
{
|
|
if (display_state)
|
|
{
|
|
if (mImageHoverSelected)
|
|
{
|
|
mImagep = mImageHoverSelected;
|
|
}
|
|
else
|
|
{
|
|
mImagep = mImageSelected;
|
|
use_glow_effect = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mImageHoverUnselected)
|
|
{
|
|
mImagep = mImageHoverUnselected;
|
|
}
|
|
else
|
|
{
|
|
mImagep = mImageUnselected;
|
|
use_glow_effect = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else if ( display_state )
|
|
{
|
|
mImagep = mImageSelected;
|
|
}
|
|
else
|
|
{
|
|
mImagep = 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() && ( (mEnabled && mTentative) || (!mEnabled && display_state ) ) )
|
|
{
|
|
mImagep = mImageDisabledSelected;
|
|
}
|
|
else if (!mImageDisabled.isNull() && !mEnabled && !display_state)
|
|
{
|
|
mImagep = mImageDisabled;
|
|
}
|
|
|
|
if (mNeedsHighlight && !mImagep)
|
|
{
|
|
use_glow_effect = TRUE;
|
|
}
|
|
|
|
// Figure out appropriate color for the text
|
|
LLColor4 label_color;
|
|
|
|
if ( mEnabled )
|
|
{
|
|
if ( !display_state )
|
|
{
|
|
label_color = mUnselectedLabelColor;
|
|
}
|
|
else
|
|
{
|
|
label_color = mSelectedLabelColor;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !display_state )
|
|
{
|
|
label_color = mDisabledLabelColor;
|
|
}
|
|
else
|
|
{
|
|
label_color = mDisabledSelectedLabelColor;
|
|
}
|
|
}
|
|
|
|
// Unselected label assignments
|
|
LLWString label;
|
|
|
|
if( display_state )
|
|
{
|
|
if( mEnabled || mDisabledSelectedLabel.empty() )
|
|
{
|
|
label = mSelectedLabel;
|
|
}
|
|
else
|
|
{
|
|
label = mDisabledSelectedLabel;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( mEnabled || mDisabledLabel.empty() )
|
|
{
|
|
label = mUnselectedLabel;
|
|
}
|
|
else
|
|
{
|
|
label = mDisabledLabel;
|
|
}
|
|
}
|
|
|
|
// draw default button border
|
|
if (mEnabled && mBorderEnabled && gFocusMgr.getAppHasFocus()) // because we're the default button in a panel
|
|
{
|
|
drawBorder(LLUI::sColorsGroup->getColor( "ButtonBorderColor" ), BORDER_SIZE);
|
|
}
|
|
|
|
// overlay with keyboard focus border
|
|
if (hasFocus())
|
|
{
|
|
F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
|
|
drawBorder(gFocusMgr.getFocusColor(), llround(lerp(1.f, 3.f, lerp_amt)));
|
|
}
|
|
|
|
if (use_glow_effect)
|
|
{
|
|
mCurGlowStrength = lerp(mCurGlowStrength, mHoverGlowStrength, LLCriticalDamp::getInterpolant(0.05f));
|
|
}
|
|
else
|
|
{
|
|
mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLCriticalDamp::getInterpolant(0.05f));
|
|
}
|
|
|
|
// Draw button image, if available.
|
|
// Otherwise draw basic rectangular button.
|
|
if( mImagep.notNull() && !mScaleImage)
|
|
{
|
|
gl_draw_image( 0, 0, mImagep, mEnabled ? mImageColor : mDisabledImageColor );
|
|
if (mCurGlowStrength > 0.01f)
|
|
{
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
gl_draw_scaled_image_with_border(0, 0, 0, 0, mImagep->getWidth(), mImagep->getHeight(), mImagep, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength), TRUE);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
}
|
|
else
|
|
if ( mImagep.notNull() && mScaleImage)
|
|
{
|
|
gl_draw_scaled_image_with_border(0, 0, mFixedWidth, mFixedHeight, mRect.getWidth(), mRect.getHeight(),
|
|
mImagep, mEnabled ? mImageColor : mDisabledImageColor );
|
|
if (mCurGlowStrength > 0.01f)
|
|
{
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
gl_draw_scaled_image_with_border(0, 0, mFixedWidth, mFixedHeight, mRect.getWidth(), mRect.getHeight(),
|
|
mImagep, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength), TRUE);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no image
|
|
llwarns << "No image for button " << mName << llendl;
|
|
// draw it in pink so we can find it
|
|
gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0, LLColor4::pink1, FALSE);
|
|
}
|
|
|
|
// draw overlay image
|
|
if (mImageOverlay.notNull())
|
|
{
|
|
const S32 IMG_PAD = 4;
|
|
// get max width and height (discard level 0)
|
|
S32 overlay_width = mImageOverlay->getWidth(0);
|
|
S32 overlay_height = mImageOverlay->getHeight(0);
|
|
|
|
F32 scale_factor = llmin((F32)mRect.getWidth() / (F32)overlay_width, (F32)mRect.getHeight() / (F32)overlay_height, 1.f);
|
|
overlay_width = llround((F32)overlay_width * scale_factor);
|
|
overlay_height = llround((F32)overlay_height * scale_factor);
|
|
|
|
S32 center_x = getLocalRect().getCenterX();
|
|
S32 center_y = getLocalRect().getCenterY();
|
|
|
|
switch(mImageOverlayAlignment)
|
|
{
|
|
case LLFontGL::LEFT:
|
|
gl_draw_scaled_image(
|
|
IMG_PAD,
|
|
center_y - (overlay_height / 2),
|
|
overlay_width,
|
|
overlay_height,
|
|
mImageOverlay,
|
|
LLColor4::white);
|
|
break;
|
|
case LLFontGL::HCENTER:
|
|
gl_draw_scaled_image(
|
|
center_x - (overlay_width / 2),
|
|
center_y - (overlay_height / 2),
|
|
overlay_width,
|
|
overlay_height,
|
|
mImageOverlay,
|
|
LLColor4::white);
|
|
break;
|
|
case LLFontGL::RIGHT:
|
|
gl_draw_scaled_image(
|
|
mRect.getWidth() - IMG_PAD - overlay_width,
|
|
center_y - (overlay_height / 2),
|
|
overlay_width,
|
|
overlay_height,
|
|
mImageOverlay,
|
|
LLColor4::white);
|
|
break;
|
|
default:
|
|
// draw nothing
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Draw label
|
|
if( !label.empty() )
|
|
{
|
|
S32 drawable_width = mRect.getWidth() - mLeftHPad - mRightHPad;
|
|
|
|
LLWString::trim(label);
|
|
|
|
S32 x;
|
|
switch( mHAlign )
|
|
{
|
|
case LLFontGL::RIGHT:
|
|
x = mRect.getWidth() - mRightHPad;
|
|
break;
|
|
case LLFontGL::HCENTER:
|
|
x = mRect.getWidth() / 2;
|
|
break;
|
|
case LLFontGL::LEFT:
|
|
default:
|
|
x = mLeftHPad;
|
|
break;
|
|
}
|
|
|
|
S32 y_offset = 2 + (mRect.getHeight() - 20)/2;
|
|
|
|
if (pressed || display_state)
|
|
{
|
|
y_offset--;
|
|
x++;
|
|
}
|
|
|
|
mGLFont->render(label, 0, (F32)x, (F32)(LLBUTTON_V_PAD + y_offset),
|
|
label_color,
|
|
mHAlign, LLFontGL::BOTTOM,
|
|
mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NORMAL,
|
|
U32_MAX, drawable_width,
|
|
NULL, FALSE, FALSE);
|
|
}
|
|
|
|
if (sDebugRects
|
|
|| (LLView::sEditingUI && this == LLView::sEditingUIView))
|
|
{
|
|
drawDebugRect();
|
|
}
|
|
}
|
|
// reset hover status for next frame
|
|
mNeedsHighlight = FALSE;
|
|
}
|
|
|
|
void LLButton::drawBorder(const LLColor4& color, S32 size)
|
|
{
|
|
S32 left = -size;
|
|
S32 top = mRect.getHeight() + size;
|
|
S32 right = mRect.getWidth() + size;
|
|
S32 bottom = -size;
|
|
|
|
if (mImagep.isNull())
|
|
{
|
|
gl_rect_2d(left, top, right, bottom, color, FALSE);
|
|
return;
|
|
}
|
|
|
|
if (mScaleImage)
|
|
{
|
|
gl_draw_scaled_image_with_border(left, bottom, mFixedWidth, mFixedHeight, right-left, top-bottom,
|
|
mImagep, color, TRUE );
|
|
}
|
|
else
|
|
{
|
|
gl_draw_scaled_image_with_border(left, bottom, 0, 0, mImagep->getWidth() + size * 2,
|
|
mImagep->getHeight() + size * 2, mImagep, color, TRUE );
|
|
}
|
|
}
|
|
|
|
void LLButton::setClickedCallback(void (*cb)(void*), void* userdata)
|
|
{
|
|
mClickedCallback = cb;
|
|
if (userdata)
|
|
{
|
|
mCallbackUserData = userdata;
|
|
}
|
|
}
|
|
|
|
|
|
void LLButton::setToggleState(BOOL b)
|
|
{
|
|
if( b != mToggleState )
|
|
{
|
|
mToggleState = b;
|
|
LLValueChangedEvent *evt = new LLValueChangedEvent(this, mToggleState);
|
|
fireEvent(evt, "");
|
|
}
|
|
}
|
|
|
|
void LLButton::setValue(const LLSD& value )
|
|
{
|
|
mToggleState = value.asBoolean();
|
|
}
|
|
|
|
LLSD LLButton::getValue() const
|
|
{
|
|
return mToggleState;
|
|
}
|
|
|
|
void LLButton::setLabel( const LLString& label )
|
|
{
|
|
setLabelUnselected(label);
|
|
setLabelSelected(label);
|
|
}
|
|
|
|
//virtual
|
|
BOOL LLButton::setLabelArg( const LLString& key, const LLString& text )
|
|
{
|
|
mUnselectedLabel.setArg(key, text);
|
|
mSelectedLabel.setArg(key, text);
|
|
return TRUE;
|
|
}
|
|
|
|
void LLButton::setLabelUnselected( const LLString& label )
|
|
{
|
|
mUnselectedLabel = label;
|
|
}
|
|
|
|
void LLButton::setLabelSelected( const LLString& label )
|
|
{
|
|
mSelectedLabel = label;
|
|
}
|
|
|
|
void LLButton::setDisabledLabel( const LLString& label )
|
|
{
|
|
mDisabledLabel = label;
|
|
}
|
|
|
|
void LLButton::setDisabledSelectedLabel( const LLString& label )
|
|
{
|
|
mDisabledSelectedLabel = label;
|
|
}
|
|
|
|
void LLButton::setImageUnselectedID( const LLUUID &image_id )
|
|
{
|
|
mImageUnselectedName = "";
|
|
mImageUnselected = LLUI::sImageProvider->getUIImageByID(image_id);
|
|
}
|
|
|
|
void LLButton::setImages( const LLString &image_name, const LLString &selected_name )
|
|
{
|
|
setImageUnselected(image_name);
|
|
setImageSelected(selected_name);
|
|
|
|
}
|
|
|
|
void LLButton::setImageSelectedID( const LLUUID &image_id )
|
|
{
|
|
mImageSelectedName = "";
|
|
mImageSelected = LLUI::sImageProvider->getUIImageByID(image_id);
|
|
}
|
|
|
|
void LLButton::setImageColor(const LLColor4& c)
|
|
{
|
|
mImageColor = c;
|
|
}
|
|
|
|
|
|
void LLButton::setImageDisabledID( const LLUUID &image_id )
|
|
{
|
|
mImageDisabledName = "";
|
|
mImageDisabled = LLUI::sImageProvider->getUIImageByID(image_id);
|
|
mDisabledImageColor = mImageColor;
|
|
mDisabledImageColor.mV[VALPHA] *= 0.5f;
|
|
}
|
|
|
|
void LLButton::setImageDisabledSelectedID( const LLUUID &image_id )
|
|
{
|
|
mImageDisabledSelectedName = "";
|
|
mImageDisabledSelected = LLUI::sImageProvider->getUIImageByID(image_id);
|
|
mDisabledImageColor = mImageColor;
|
|
mDisabledImageColor.mV[VALPHA] *= 0.5f;
|
|
}
|
|
|
|
void LLButton::setDisabledImages( const LLString &image_name, const LLString &selected_name, const LLColor4& c )
|
|
{
|
|
setImageDisabled(image_name);
|
|
setImageDisabledSelected(selected_name);
|
|
mDisabledImageColor = c;
|
|
}
|
|
|
|
|
|
void LLButton::setImageHoverSelectedID( const LLUUID& image_id )
|
|
{
|
|
mImageHoverSelectedName = "";
|
|
mImageHoverSelected = LLUI::sImageProvider->getUIImageByID(image_id);
|
|
}
|
|
|
|
void LLButton::setDisabledImages( const LLString &image_name, const LLString &selected_name)
|
|
{
|
|
LLColor4 clr = mImageColor;
|
|
clr.mV[VALPHA] *= .5f;
|
|
setDisabledImages( image_name, selected_name, clr );
|
|
}
|
|
|
|
void LLButton::setImageHoverUnselectedID( const LLUUID& image_id )
|
|
{
|
|
mImageHoverUnselectedName = "";
|
|
mImageHoverUnselected = LLUI::sImageProvider->getUIImageByID(image_id);
|
|
}
|
|
|
|
void LLButton::setHoverImages( const LLString& image_name, const LLString& selected_name )
|
|
{
|
|
setImageHoverUnselected(image_name);
|
|
setImageHoverSelected(selected_name);
|
|
}
|
|
|
|
void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment)
|
|
{
|
|
if (image_name.empty())
|
|
{
|
|
mImageOverlay = NULL;
|
|
}
|
|
else
|
|
{
|
|
LLUUID overlay_image_id = LLUI::findAssetUUIDByName(image_name);
|
|
mImageOverlay = LLUI::sImageProvider->getUIImageByID(overlay_image_id);
|
|
mImageOverlayAlignment = alignment;
|
|
}
|
|
}
|
|
|
|
|
|
void LLButton::onMouseCaptureLost()
|
|
{
|
|
mMouseDownTimer.stop();
|
|
mMouseDownTimer.reset();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// LLSquareButton
|
|
//-------------------------------------------------------------------------
|
|
LLSquareButton::LLSquareButton(const LLString& name, const LLRect& rect,
|
|
const LLString& label,
|
|
const LLFontGL *font,
|
|
const LLString& control_name,
|
|
void (*click_callback)(void*),
|
|
void *callback_data,
|
|
const LLString& selected_label )
|
|
: LLButton(name, rect, "","",
|
|
control_name,
|
|
click_callback, callback_data,
|
|
font,
|
|
label,
|
|
(selected_label.empty() ? label : selected_label) )
|
|
{
|
|
setImageUnselected("square_btn_32x128.tga");
|
|
// mImageUnselected = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_32x128.tga")));
|
|
setImageSelected("square_btn_selected_32x128.tga");
|
|
// mImageSelectedImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_selected_32x128.tga")));
|
|
setImageDisabled("square_btn_32x128.tga");
|
|
//mDisabledImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_32x128.tga")));
|
|
setImageDisabledSelected("square_btn_selected_32x128.tga");
|
|
//mDisabledSelectedImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_selected_32x128.tga")));
|
|
mImageColor = LLUI::sColorsGroup->getColor("ButtonColor");
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// 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::setImageUnselected(const LLString &image_name)
|
|
{
|
|
setImageUnselectedID(LLUI::findAssetUUIDByName(image_name));
|
|
mImageUnselectedName = image_name;
|
|
}
|
|
|
|
void LLButton::setImageSelected(const LLString &image_name)
|
|
{
|
|
setImageSelectedID(LLUI::findAssetUUIDByName(image_name));
|
|
mImageSelectedName = image_name;
|
|
}
|
|
|
|
void LLButton::setImageHoverSelected(const LLString &image_name)
|
|
{
|
|
setImageHoverSelectedID(LLUI::findAssetUUIDByName(image_name));
|
|
mImageHoverSelectedName = image_name;
|
|
}
|
|
|
|
void LLButton::setImageHoverUnselected(const LLString &image_name)
|
|
{
|
|
setImageHoverUnselectedID(LLUI::findAssetUUIDByName(image_name));
|
|
mImageHoverUnselectedName = image_name;
|
|
}
|
|
|
|
void LLButton::setImageDisabled(const LLString &image_name)
|
|
{
|
|
setImageDisabledID(LLUI::findAssetUUIDByName(image_name));
|
|
mImageDisabledName = image_name;
|
|
}
|
|
|
|
void LLButton::setImageDisabledSelected(const LLString &image_name)
|
|
{
|
|
setImageDisabledSelectedID(LLUI::findAssetUUIDByName(image_name));
|
|
mImageDisabledSelectedName = image_name;
|
|
}
|
|
|
|
void LLButton::addImageAttributeToXML(LLXMLNodePtr node,
|
|
const LLString& image_name,
|
|
const LLUUID& image_id,
|
|
const LLString& xml_tag_name) const
|
|
{
|
|
if( !image_name.empty() )
|
|
{
|
|
node->createChild(xml_tag_name, TRUE)->setStringValue(image_name);
|
|
}
|
|
else if( image_id != LLUUID::null )
|
|
{
|
|
node->createChild(xml_tag_name + "_id", TRUE)->setUUIDValue(image_id);
|
|
}
|
|
}
|
|
|
|
// virtual
|
|
LLXMLNodePtr LLButton::getXML(bool save_children) const
|
|
{
|
|
LLXMLNodePtr node = LLUICtrl::getXML();
|
|
|
|
node->createChild("label", TRUE)->setStringValue(getLabelUnselected());
|
|
node->createChild("label_selected", TRUE)->setStringValue(getLabelSelected());
|
|
node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont));
|
|
node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign));
|
|
node->createChild("border_width", TRUE)->setIntValue(mFixedWidth);
|
|
node->createChild("border_height", TRUE)->setIntValue(mFixedHeight);
|
|
|
|
addImageAttributeToXML(node,mImageUnselectedName,mImageUnselectedID,"image_unselected");
|
|
addImageAttributeToXML(node,mImageSelectedName,mImageSelectedID,"image_selected");
|
|
addImageAttributeToXML(node,mImageHoverSelectedName,mImageHoverSelectedID,"image_hover_selected");
|
|
addImageAttributeToXML(node,mImageHoverUnselectedName,mImageHoverUnselectedID,"image_hover_unselected");
|
|
addImageAttributeToXML(node,mImageDisabledName,mImageDisabledID,"image_disabled");
|
|
addImageAttributeToXML(node,mImageDisabledSelectedName,mImageDisabledSelectedID,"image_disabled_selected");
|
|
|
|
node->createChild("scale_image", TRUE)->setBoolValue(mScaleImage);
|
|
|
|
return node;
|
|
}
|
|
|
|
void clicked_help(void* data)
|
|
{
|
|
LLButton* self = (LLButton*)data;
|
|
if (!self) return;
|
|
|
|
if (!LLUI::sHtmlHelp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLUI::sHtmlHelp->show(self->getHelpURL());
|
|
}
|
|
|
|
// static
|
|
LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
|
|
{
|
|
LLString name("button");
|
|
node->getAttributeString("name", name);
|
|
|
|
LLString label = name;
|
|
node->getAttributeString("label", label);
|
|
|
|
LLString label_selected = label;
|
|
node->getAttributeString("label_selected", label_selected);
|
|
|
|
LLFontGL* font = selectFont(node);
|
|
|
|
LLString image_unselected;
|
|
if (node->hasAttribute("image_unselected")) node->getAttributeString("image_unselected",image_unselected);
|
|
|
|
LLString image_selected;
|
|
if (node->hasAttribute("image_selected")) node->getAttributeString("image_selected",image_selected);
|
|
|
|
LLString image_hover_selected;
|
|
if (node->hasAttribute("image_hover_selected")) node->getAttributeString("image_hover_selected",image_hover_selected);
|
|
|
|
LLString image_hover_unselected;
|
|
if (node->hasAttribute("image_hover_unselected")) node->getAttributeString("image_hover_unselected",image_hover_unselected);
|
|
|
|
LLString image_disabled_selected;
|
|
if (node->hasAttribute("image_disabled_selected")) node->getAttributeString("image_disabled_selected",image_disabled_selected);
|
|
|
|
LLString image_disabled;
|
|
if (node->hasAttribute("image_disabled")) node->getAttributeString("image_disabled",image_disabled);
|
|
|
|
LLString image_overlay;
|
|
node->getAttributeString("image_overlay", image_overlay);
|
|
|
|
LLFontGL::HAlign image_overlay_alignment = LLFontGL::HCENTER;
|
|
LLString image_overlay_alignment_string;
|
|
if (node->hasAttribute("image_overlay_alignment"))
|
|
{
|
|
node->getAttributeString("image_overlay_alignment", image_overlay_alignment_string);
|
|
image_overlay_alignment = LLFontGL::hAlignFromName(image_overlay_alignment_string);
|
|
}
|
|
|
|
|
|
LLButton *button = new LLButton(name,
|
|
LLRect(),
|
|
image_unselected,
|
|
image_selected,
|
|
"",
|
|
NULL,
|
|
parent,
|
|
font,
|
|
label,
|
|
label_selected);
|
|
|
|
node->getAttributeS32("border_width", button->mFixedWidth);
|
|
node->getAttributeS32("border_height", button->mFixedHeight);
|
|
|
|
if(image_hover_selected != LLString::null) button->setImageHoverSelected(image_hover_selected);
|
|
|
|
if(image_hover_unselected != LLString::null) button->setImageHoverUnselected(image_hover_unselected);
|
|
|
|
if(image_disabled_selected != LLString::null) button->setImageDisabledSelected(image_disabled_selected );
|
|
|
|
if(image_disabled != LLString::null) button->setImageDisabled(image_disabled);
|
|
|
|
if(image_overlay != LLString::null) button->setImageOverlay(image_overlay, image_overlay_alignment);
|
|
|
|
if (node->hasAttribute("halign"))
|
|
{
|
|
LLFontGL::HAlign halign = selectFontHAlign(node);
|
|
button->setHAlign(halign);
|
|
}
|
|
|
|
if (node->hasAttribute("scale_image"))
|
|
{
|
|
BOOL needsScale = FALSE;
|
|
node->getAttributeBOOL("scale_image",needsScale);
|
|
button->setScaleImage( needsScale );
|
|
}
|
|
|
|
if(label.empty())
|
|
{
|
|
button->setLabelUnselected(node->getTextContents());
|
|
}
|
|
if (label_selected.empty())
|
|
{
|
|
button->setLabelSelected(node->getTextContents());
|
|
}
|
|
|
|
if (node->hasAttribute("help_url"))
|
|
{
|
|
LLString help_url;
|
|
node->getAttributeString("help_url",help_url);
|
|
button->setHelpURLCallback(help_url);
|
|
}
|
|
|
|
button->initFromXML(node, parent);
|
|
|
|
return button;
|
|
}
|
|
|
|
void LLButton::setHelpURLCallback(std::string help_url)
|
|
{
|
|
mHelpURL = help_url;
|
|
setClickedCallback(clicked_help,this);
|
|
}
|