353 lines
8.7 KiB
C++
353 lines
8.7 KiB
C++
/**
|
|
* @file llslider.cpp
|
|
* @brief LLSlider base class
|
|
*
|
|
* Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
|
|
* $License$
|
|
*/
|
|
|
|
#include "linden_common.h"
|
|
|
|
#include "llslider.h"
|
|
#include "llui.h"
|
|
|
|
#include "llgl.h"
|
|
#include "llwindow.h"
|
|
#include "llfocusmgr.h"
|
|
#include "llkeyboard.h" // for the MASK constants
|
|
#include "llcontrol.h"
|
|
#include "llimagegl.h"
|
|
|
|
const S32 THUMB_WIDTH = 8;
|
|
const S32 TRACK_HEIGHT = 6;
|
|
|
|
LLSlider::LLSlider(
|
|
const LLString& name,
|
|
const LLRect& rect,
|
|
void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata),
|
|
void* callback_userdata,
|
|
F32 initial_value,
|
|
F32 min_value,
|
|
F32 max_value,
|
|
F32 increment,
|
|
const LLString& control_name)
|
|
:
|
|
LLUICtrl( name, rect, TRUE, on_commit_callback, callback_userdata,
|
|
FOLLOWS_LEFT | FOLLOWS_TOP),
|
|
mValue( initial_value ),
|
|
mInitialValue( initial_value ),
|
|
mMinValue( min_value ),
|
|
mMaxValue( max_value ),
|
|
mIncrement( increment ),
|
|
mMouseOffset( 0 ),
|
|
mDragStartThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
|
|
mThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
|
|
mTrackColor( LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ),
|
|
mThumbOutlineColor( LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ),
|
|
mThumbCenterColor( LLUI::sColorsGroup->getColor( "SliderThumbCenterColor" ) ),
|
|
mDisabledThumbColor(LLUI::sColorsGroup->getColor( "SliderDisabledThumbColor" ) ),
|
|
mMouseDownCallback( NULL ),
|
|
mMouseUpCallback( NULL )
|
|
{
|
|
// prperly handle setting the starting thumb rect
|
|
// do it this way to handle both the operating-on-settings
|
|
// and standalone ways of using this
|
|
setControlName(control_name, NULL);
|
|
setValue(getValueF32());
|
|
}
|
|
|
|
EWidgetType LLSlider::getWidgetType() const
|
|
{
|
|
return WIDGET_TYPE_SLIDER_BAR;
|
|
}
|
|
|
|
LLString LLSlider::getWidgetTag() const
|
|
{
|
|
return LL_SLIDER_TAG;
|
|
}
|
|
|
|
void LLSlider::setValue(F32 value, BOOL from_event)
|
|
{
|
|
value = llclamp( value, mMinValue, mMaxValue );
|
|
|
|
// Round to nearest increment (bias towards rounding down)
|
|
value -= mMinValue;
|
|
value += mIncrement/2.0001f;
|
|
value -= fmod(value, mIncrement);
|
|
mValue = mMinValue + value;
|
|
|
|
if (!from_event)
|
|
{
|
|
setControlValue(mValue);
|
|
}
|
|
|
|
F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
|
|
|
|
S32 left_edge = THUMB_WIDTH/2;
|
|
S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
|
|
|
|
S32 x = left_edge + S32( t * (right_edge - left_edge) );
|
|
mThumbRect.mLeft = x - (THUMB_WIDTH/2);
|
|
mThumbRect.mRight = x + (THUMB_WIDTH/2);
|
|
}
|
|
|
|
F32 LLSlider::getValueF32() const
|
|
{
|
|
return mValue;
|
|
}
|
|
|
|
BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask)
|
|
{
|
|
if( gFocusMgr.getMouseCapture() == this )
|
|
{
|
|
S32 left_edge = THUMB_WIDTH/2;
|
|
S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
|
|
|
|
x += mMouseOffset;
|
|
x = llclamp( x, left_edge, right_edge );
|
|
|
|
F32 t = F32(x - left_edge) / (right_edge - left_edge);
|
|
setValue(t * (mMaxValue - mMinValue) + mMinValue );
|
|
onCommit();
|
|
|
|
getWindow()->setCursor(UI_CURSOR_ARROW);
|
|
lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;
|
|
}
|
|
else
|
|
{
|
|
getWindow()->setCursor(UI_CURSOR_ARROW);
|
|
lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLSlider::handleMouseUp(S32 x, S32 y, MASK mask)
|
|
{
|
|
BOOL handled = FALSE;
|
|
|
|
if( gFocusMgr.getMouseCapture() == this )
|
|
{
|
|
gFocusMgr.setMouseCapture( NULL, NULL );
|
|
|
|
if( mMouseUpCallback )
|
|
{
|
|
mMouseUpCallback( this, mCallbackUserData );
|
|
}
|
|
handled = TRUE;
|
|
make_ui_sound("UISndClickRelease");
|
|
}
|
|
else
|
|
{
|
|
handled = TRUE;
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
|
|
{
|
|
// only do sticky-focus on non-chrome widgets
|
|
if (!getIsChrome())
|
|
{
|
|
setFocus(TRUE);
|
|
}
|
|
if( mMouseDownCallback )
|
|
{
|
|
mMouseDownCallback( this, mCallbackUserData );
|
|
}
|
|
|
|
if (MASK_CONTROL & mask) // if CTRL is modifying
|
|
{
|
|
setValue(mInitialValue);
|
|
onCommit();
|
|
}
|
|
else
|
|
{
|
|
// Find the offset of the actual mouse location from the center of the thumb.
|
|
if (mThumbRect.pointInRect(x,y))
|
|
{
|
|
mMouseOffset = (mThumbRect.mLeft + THUMB_WIDTH/2) - x;
|
|
}
|
|
else
|
|
{
|
|
mMouseOffset = 0;
|
|
}
|
|
|
|
// Start dragging the thumb
|
|
// No handler needed for focus lost since this class has no state that depends on it.
|
|
gFocusMgr.setMouseCapture( this, NULL );
|
|
mDragStartThumbRect = mThumbRect;
|
|
}
|
|
make_ui_sound("UISndClick");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLSlider::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
|
|
{
|
|
BOOL handled = FALSE;
|
|
if( getVisible() && mEnabled && !called_from_parent )
|
|
{
|
|
switch(key)
|
|
{
|
|
case KEY_UP:
|
|
case KEY_DOWN:
|
|
// eat up and down keys to be consistent
|
|
handled = TRUE;
|
|
break;
|
|
case KEY_LEFT:
|
|
setValue(getValueF32() - getIncrement());
|
|
onCommit();
|
|
handled = TRUE;
|
|
break;
|
|
case KEY_RIGHT:
|
|
setValue(getValueF32() + getIncrement());
|
|
onCommit();
|
|
handled = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
void LLSlider::draw()
|
|
{
|
|
if( getVisible() )
|
|
{
|
|
// Draw background and thumb.
|
|
|
|
// drawing solids requires texturing be disabled
|
|
LLGLSNoTexture no_texture;
|
|
|
|
LLRect rect(mDragStartThumbRect);
|
|
|
|
F32 opacity = mEnabled ? 1.f : 0.3f;
|
|
|
|
// Track
|
|
|
|
LLUUID thumb_image_id;
|
|
thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga"));
|
|
LLImageGL* thumb_imagep = LLUI::sImageProvider->getUIImageByID(thumb_image_id);
|
|
|
|
S32 height_offset = (mRect.getHeight() - TRACK_HEIGHT) / 2;
|
|
LLRect track_rect(0, mRect.getHeight() - height_offset, mRect.getWidth(), height_offset );
|
|
|
|
track_rect.stretch(-1);
|
|
gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(),
|
|
thumb_imagep, mTrackColor % opacity);
|
|
//gl_rect_2d( track_rect, mThumbOutlineColor % opacity );
|
|
|
|
if (!thumb_imagep)
|
|
{
|
|
gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE);
|
|
if (gFocusMgr.getMouseCapture() == this)
|
|
{
|
|
gl_rect_2d(mDragStartThumbRect, mThumbCenterColor % opacity, FALSE);
|
|
}
|
|
}
|
|
else if( gFocusMgr.getMouseCapture() == this )
|
|
{
|
|
gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, 16, 16, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(),
|
|
thumb_imagep, mThumbCenterColor % 0.3f, TRUE);
|
|
|
|
if (hasFocus())
|
|
{
|
|
F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
|
|
LLRect highlight_rect = mThumbRect;
|
|
highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
|
|
gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
|
|
thumb_imagep, gFocusMgr.getFocusColor());
|
|
}
|
|
|
|
|
|
gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(),
|
|
thumb_imagep, mThumbOutlineColor, TRUE);
|
|
|
|
//// Start Thumb
|
|
//gl_rect_2d( mDragStartThumbRect, mThumbOutlineColor % 0.3f );
|
|
//rect.stretch(-1);
|
|
//gl_rect_2d( rect, mThumbCenterColor % 0.3f );
|
|
|
|
//// Thumb
|
|
//gl_rect_2d( mThumbRect, mThumbOutlineColor );
|
|
}
|
|
else
|
|
{
|
|
if (hasFocus())
|
|
{
|
|
F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
|
|
LLRect highlight_rect = mThumbRect;
|
|
highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
|
|
gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
|
|
thumb_imagep, gFocusMgr.getFocusColor());
|
|
}
|
|
|
|
gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(),
|
|
thumb_imagep, mThumbCenterColor % opacity, TRUE);
|
|
//rect = mThumbRect;
|
|
|
|
//gl_rect_2d( mThumbRect, mThumbOutlineColor % opacity );
|
|
//
|
|
//rect.stretch(-1);
|
|
|
|
//// Thumb
|
|
//gl_rect_2d( rect, mThumbCenterColor % opacity );
|
|
|
|
}
|
|
|
|
LLUICtrl::draw();
|
|
}
|
|
}
|
|
|
|
// virtual
|
|
LLXMLNodePtr LLSlider::getXML(bool save_children) const
|
|
{
|
|
LLXMLNodePtr node = LLUICtrl::getXML();
|
|
|
|
node->createChild("initial_val", TRUE)->setFloatValue(getInitialValue());
|
|
node->createChild("min_val", TRUE)->setFloatValue(getMinValue());
|
|
node->createChild("max_val", TRUE)->setFloatValue(getMaxValue());
|
|
node->createChild("increment", TRUE)->setFloatValue(getIncrement());
|
|
|
|
return node;
|
|
}
|
|
|
|
|
|
//static
|
|
LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
|
|
{
|
|
LLString name("slider_bar");
|
|
node->getAttributeString("name", name);
|
|
|
|
LLRect rect;
|
|
createRect(node, rect, parent, LLRect());
|
|
|
|
F32 initial_value = 0.f;
|
|
node->getAttributeF32("initial_val", initial_value);
|
|
|
|
F32 min_value = 0.f;
|
|
node->getAttributeF32("min_val", min_value);
|
|
|
|
F32 max_value = 1.f;
|
|
node->getAttributeF32("max_val", max_value);
|
|
|
|
F32 increment = 0.1f;
|
|
node->getAttributeF32("increment", increment);
|
|
|
|
|
|
LLSlider* slider = new LLSlider(name,
|
|
rect,
|
|
NULL,
|
|
NULL,
|
|
initial_value,
|
|
min_value,
|
|
max_value,
|
|
increment);
|
|
|
|
slider->initFromXML(node, parent);
|
|
|
|
return slider;
|
|
}
|