diff options
Diffstat (limited to 'indra/llui/llsliderctrl.cpp')
-rw-r--r-- | indra/llui/llsliderctrl.cpp | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp new file mode 100644 index 0000000000..6c740aa39e --- /dev/null +++ b/indra/llui/llsliderctrl.cpp @@ -0,0 +1,538 @@ +/** + * @file llsliderctrl.cpp + * @brief LLSliderCtrl base class + * + * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "linden_common.h" + +#include "llsliderctrl.h" + +#include "audioengine.h" +#include "sound_ids.h" + +#include "llmath.h" +#include "llfontgl.h" +#include "llgl.h" +#include "llkeyboard.h" +#include "lllineeditor.h" +#include "llslider.h" +#include "llstring.h" +#include "lltextbox.h" +#include "llui.h" +#include "lluiconstants.h" +#include "llcontrol.h" +#include "llfocusmgr.h" +#include "llresmgr.h" + +const U32 MAX_STRING_LENGTH = 10; + + +LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect, + const LLString& label, + const LLFontGL* font, + S32 label_width, + S32 text_left, + BOOL show_text, + BOOL can_edit_text, + void (*commit_callback)(LLUICtrl*, void*), + void* callback_user_data, + F32 initial_value, F32 min_value, F32 max_value, F32 increment, + const LLString& control_which) + : LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data ), + mFont(font), + mShowText( show_text ), + mCanEditText( can_edit_text ), + mPrecision( 3 ), + mLabelBox( NULL ), + mLabelWidth( label_width ), + mValue( initial_value ), + mEditor( NULL ), + mTextBox( NULL ), + mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), + mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), + mSliderMouseUpCallback( NULL ), + mSliderMouseDownCallback( NULL ) +{ + S32 top = mRect.getHeight(); + S32 bottom = 0; + S32 left = 0; + + // Label + if( !label.empty() ) + { + if (label_width == 0) + { + label_width = font->getWidth(label); + } + LLRect label_rect( left, top, label_width, bottom ); + mLabelBox = new LLTextBox( "SliderCtrl Label", label_rect, label.c_str(), font ); + addChild(mLabelBox); + } + + S32 slider_right = mRect.getWidth(); + if( show_text ) + { + slider_right = text_left - SLIDERCTRL_SPACING; + } + + S32 slider_left = label_width ? label_width + SLIDERCTRL_SPACING : 0; + LLRect slider_rect( slider_left, top, slider_right, bottom ); + mSlider = new LLSlider( + "slider", + slider_rect, + LLSliderCtrl::onSliderCommit, this, + initial_value, min_value, max_value, increment, + control_which ); + addChild( mSlider ); + + if( show_text ) + { + LLRect text_rect( text_left, top, mRect.getWidth(), bottom ); + if( can_edit_text ) + { + mEditor = new LLLineEditor( "SliderCtrl Editor", text_rect, + "", font, + MAX_STRING_LENGTH, + &LLSliderCtrl::onEditorCommit, NULL, NULL, this, + &LLLineEditor::prevalidateFloat ); + mEditor->setFollowsLeft(); + mEditor->setFollowsBottom(); + mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus ); + mEditor->setIgnoreTab(TRUE); + // don't do this, as selecting the entire text is single clicking in some cases + // and double clicking in others + //mEditor->setSelectAllonFocusReceived(TRUE); + addChild(mEditor); + } + else + { + mTextBox = new LLTextBox( "SliderCtrl Text", text_rect, "", font); + mTextBox->setFollowsLeft(); + mTextBox->setFollowsBottom(); + addChild(mTextBox); + } + } + + updateText(); +} + +LLSliderCtrl::~LLSliderCtrl() +{ + // Children all cleaned up by default view destructor. +} + +// static +void LLSliderCtrl::onEditorGainFocus( LLUICtrl* caller, void *userdata ) +{ + LLSliderCtrl* self = (LLSliderCtrl*) userdata; + llassert( caller == self->mEditor ); + + self->onFocusReceived(); +} + +F32 LLSliderCtrl::getValueF32() const +{ + return mSlider->getValueF32(); +} + +void LLSliderCtrl::setValue(F32 v, BOOL from_event) +{ + mSlider->setValue( v, from_event ); + mValue = mSlider->getValueF32(); + updateText(); +} + +BOOL LLSliderCtrl::setLabelArg( const LLString& key, const LLString& text ) +{ + BOOL res = FALSE; + if (mLabelBox) + { + res = mLabelBox->setTextArg(key, text); + if (res && mLabelWidth == 0) + { + S32 label_width = mFont->getWidth(mLabelBox->getText()); + LLRect rect = mLabelBox->getRect(); + S32 prev_right = rect.mRight; + rect.mRight = rect.mLeft + label_width; + mLabelBox->setRect(rect); + + S32 delta = rect.mRight - prev_right; + rect = mSlider->getRect(); + S32 left = rect.mLeft + delta; + left = llclamp(left, 0, rect.mRight-SLIDERCTRL_SPACING); + rect.mLeft = left; + mSlider->setRect(rect); + } + } + return res; +} + +void LLSliderCtrl::clear() +{ + setValue(0.0f); + if( mEditor ) + { + mEditor->setText( "" ); + } + if( mTextBox ) + { + mTextBox->setText( "" ); + } + +} + +BOOL LLSliderCtrl::isMouseHeldDown() +{ + return gFocusMgr.getMouseCapture() == mSlider; +} + +void LLSliderCtrl::updateText() +{ + if( mEditor || mTextBox ) + { + LLLocale locale(LLLocale::USER_LOCALE); + + // Don't display very small negative values as -0.000 + F32 displayed_value = (F32)(floor(getValueF32() * pow(10, mPrecision) + 0.5) / pow(10, mPrecision)); + + LLString format = llformat("%%.%df", mPrecision); + LLString text = llformat(format.c_str(), displayed_value); + if( mEditor ) + { + mEditor->setText( text ); + } + else + { + mTextBox->setText( text ); + } + } +} + +// static +void LLSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata ) +{ + LLSliderCtrl* self = (LLSliderCtrl*) userdata; + llassert( caller == self->mEditor ); + + BOOL success = FALSE; + F32 val = self->mValue; + F32 saved_val = self->mValue; + + LLString text = self->mEditor->getText(); + if( LLLineEditor::postvalidateFloat( text ) ) + { + LLLocale locale(LLLocale::USER_LOCALE); + val = (F32) atof( text.c_str() ); + if( self->mSlider->getMinValue() <= val && val <= self->mSlider->getMaxValue() ) + { + if( self->mValidateCallback ) + { + self->setValue( val ); // set the value temporarily so that the callback can retrieve it. + if( self->mValidateCallback( self, self->mCallbackUserData ) ) + { + success = TRUE; + } + } + else + { + self->setValue( val ); + success = TRUE; + } + } + } + + if( success ) + { + self->onCommit(); + } + else + { + if( self->getValueF32() != saved_val ) + { + self->setValue( saved_val ); + } + self->reportInvalidData(); + } + self->updateText(); +} + +// static +void LLSliderCtrl::onSliderCommit( LLUICtrl* caller, void *userdata ) +{ + LLSliderCtrl* self = (LLSliderCtrl*) userdata; + llassert( caller == self->mSlider ); + + BOOL success = FALSE; + F32 saved_val = self->mValue; + F32 new_val = self->mSlider->getValueF32(); + + if( self->mValidateCallback ) + { + self->mValue = new_val; // set the value temporarily so that the callback can retrieve it. + if( self->mValidateCallback( self, self->mCallbackUserData ) ) + { + success = TRUE; + } + } + else + { + self->mValue = new_val; + success = TRUE; + } + + if( success ) + { + self->onCommit(); + } + else + { + if( self->mValue != saved_val ) + { + self->setValue( saved_val ); + } + self->reportInvalidData(); + } + self->updateText(); +} + +void LLSliderCtrl::setEnabled(BOOL b) +{ + LLUICtrl::setEnabled( b ); + + if( mLabelBox ) + { + mLabelBox->setColor( b ? mTextEnabledColor : mTextDisabledColor ); + } + + mSlider->setEnabled( b ); + + if( mEditor ) + { + mEditor->setEnabled( b ); + } + + if( mTextBox ) + { + mTextBox->setColor( b ? mTextEnabledColor : mTextDisabledColor ); + } +} + + +void LLSliderCtrl::setTentative(BOOL b) +{ + if( mEditor ) + { + mEditor->setTentative(b); + } + LLUICtrl::setTentative(b); +} + + +void LLSliderCtrl::onCommit() +{ + setTentative(FALSE); + + if( mEditor ) + { + mEditor->setTentative(FALSE); + } + + LLUICtrl::onCommit(); +} + + +void LLSliderCtrl::setPrecision(S32 precision) +{ + if (precision < 0 || precision > 10) + { + llerrs << "LLSliderCtrl::setPrecision - precision out of range" << llendl; + return; + } + + mPrecision = precision; + updateText(); +} + +void LLSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) ) +{ + mSliderMouseDownCallback = slider_mousedown_callback; + mSlider->setMouseDownCallback( LLSliderCtrl::onSliderMouseDown ); +} + +// static +void LLSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata) +{ + LLSliderCtrl* self = (LLSliderCtrl*) userdata; + if( self->mSliderMouseDownCallback ) + { + self->mSliderMouseDownCallback( self, self->mCallbackUserData ); + } +} + + +void LLSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) ) +{ + mSliderMouseUpCallback = slider_mouseup_callback; + mSlider->setMouseUpCallback( LLSliderCtrl::onSliderMouseUp ); +} + +// static +void LLSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata) +{ + LLSliderCtrl* self = (LLSliderCtrl*) userdata; + if( self->mSliderMouseUpCallback ) + { + self->mSliderMouseUpCallback( self, self->mCallbackUserData ); + } +} + +void LLSliderCtrl::onTabInto() +{ + if( mEditor ) + { + mEditor->onTabInto(); + } +} + +void LLSliderCtrl::reportInvalidData() +{ + make_ui_sound("UISndBadKeystroke"); +} + +//virtual +LLString LLSliderCtrl::getControlName() const +{ + return mSlider->getControlName(); +} + +// virtual +void LLSliderCtrl::setControlName(const LLString& control_name, LLView* context) +{ + mSlider->setControlName(control_name, context); +} + +// virtual +LLXMLNodePtr LLSliderCtrl::getXML(bool save_children) const +{ + LLXMLNodePtr node = LLUICtrl::getXML(); + + node->createChild("show_text", TRUE)->setBoolValue(mShowText); + + node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText); + + node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision); + + if (mLabelBox) + { + node->createChild("label", TRUE)->setStringValue(mLabelBox->getText()); + } + + // TomY TODO: Do we really want to export the transient state of the slider? + node->createChild("value", TRUE)->setFloatValue(mValue); + + if (mSlider) + { + node->createChild("initial_val", TRUE)->setFloatValue(mSlider->getInitialValue()); + node->createChild("min_val", TRUE)->setFloatValue(mSlider->getMinValue()); + node->createChild("max_val", TRUE)->setFloatValue(mSlider->getMaxValue()); + node->createChild("increment", TRUE)->setFloatValue(mSlider->getIncrement()); + } + addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor"); + addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor"); + + return node; +} + +LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + LLString name("slider"); + node->getAttributeString("name", name); + + LLString label; + node->getAttributeString("label", label); + + LLRect rect; + createRect(node, rect, parent, LLRect()); + + LLFontGL* font = LLView::selectFont(node); + + // HACK: Font might not be specified. + if (!font) + { + font = LLFontGL::sSansSerifSmall; + } + + S32 label_width = 0; + node->getAttributeS32("label_width", label_width); + + BOOL show_text = TRUE; + node->getAttributeBOOL("show_text", show_text); + + BOOL can_edit_text = FALSE; + node->getAttributeBOOL("can_edit_text", can_edit_text); + + 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); + + U32 precision = 3; + node->getAttributeU32("decimal_digits", precision); + + S32 text_left = 0; + if (show_text) + { + // calculate the size of the text box (log max_value is number of digits - 1 so plus 1) + if ( max_value ) + text_left = font->getWidth("0") * ( static_cast < S32 > ( log10 ( max_value ) ) + precision + 1 ); + + if ( increment < 1.0f ) + text_left += font->getWidth("."); // (mostly) take account of decimal point in value + + if ( min_value < 0.0f || max_value < 0.0f ) + text_left += font->getWidth("-"); // (mostly) take account of minus sign + + // padding to make things look nicer + text_left += 8; + } + + LLUICtrlCallback callback = NULL; + + if (label.empty()) + { + label.assign(node->getTextContents()); + } + + LLSliderCtrl* slider = new LLSliderCtrl(name, + rect, + label, + font, + label_width, + rect.getWidth() - text_left, + show_text, + can_edit_text, + callback, + NULL, + initial_value, + min_value, + max_value, + increment); + + slider->setPrecision(precision); + + slider->initFromXML(node, parent); + + slider->updateText(); + + return slider; +} |