From cd17687f01420952712a500107e0f93e7ab8d5f8 Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Fri, 15 Aug 2008 23:45:34 -0500 Subject: Second Life viewer sources 1.19.1.0 --- linden/indra/llui/llmultisliderctrl.cpp | 634 ++++++++++++++++++++++++++++++++ 1 file changed, 634 insertions(+) create mode 100644 linden/indra/llui/llmultisliderctrl.cpp (limited to 'linden/indra/llui/llmultisliderctrl.cpp') diff --git a/linden/indra/llui/llmultisliderctrl.cpp b/linden/indra/llui/llmultisliderctrl.cpp new file mode 100644 index 0000000..0d23dd7 --- /dev/null +++ b/linden/indra/llui/llmultisliderctrl.cpp @@ -0,0 +1,634 @@ +/** + * @file llmultisliderctrl.cpp + * @brief LLMultiSliderCtrl base class + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llmultisliderctrl.h" + +#include "audioengine.h" +#include "sound_ids.h" + +#include "llmath.h" +#include "llfontgl.h" +#include "llgl.h" +#include "llkeyboard.h" +#include "lllineeditor.h" +#include "llmultislider.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; + + +LLMultiSliderCtrl::LLMultiSliderCtrl(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, + S32 max_sliders, BOOL allow_overlap, + BOOL draw_track, + BOOL use_triangle, + 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 ), + + mEditor( NULL ), + mTextBox( NULL ), + mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), + mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), + mSliderMouseUpCallback( NULL ), + mSliderMouseDownCallback( NULL ) +{ + S32 top = getRect().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( "MultiSliderCtrl Label", label_rect, label.c_str(), font ); + addChild(mLabelBox); + } + + S32 slider_right = getRect().getWidth(); + if( show_text ) + { + slider_right = text_left - MULTI_SLIDERCTRL_SPACING; + } + + S32 slider_left = label_width ? label_width + MULTI_SLIDERCTRL_SPACING : 0; + LLRect slider_rect( slider_left, top, slider_right, bottom ); + mMultiSlider = new LLMultiSlider( + "multi_slider", + slider_rect, + LLMultiSliderCtrl::onSliderCommit, this, + initial_value, min_value, max_value, increment, + max_sliders, allow_overlap, draw_track, + use_triangle, + control_which ); + addChild( mMultiSlider ); + mCurValue = mMultiSlider->getCurSliderValue(); + + if( show_text ) + { + LLRect text_rect( text_left, top, getRect().getWidth(), bottom ); + if( can_edit_text ) + { + mEditor = new LLLineEditor( "MultiSliderCtrl Editor", text_rect, + "", font, + MAX_STRING_LENGTH, + &LLMultiSliderCtrl::onEditorCommit, NULL, NULL, this, + &LLLineEditor::prevalidateFloat ); + mEditor->setFollowsLeft(); + mEditor->setFollowsBottom(); + mEditor->setFocusReceivedCallback( &LLMultiSliderCtrl::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( "MultiSliderCtrl Text", text_rect, "", font); + mTextBox->setFollowsLeft(); + mTextBox->setFollowsBottom(); + addChild(mTextBox); + } + } + + updateText(); +} + +LLMultiSliderCtrl::~LLMultiSliderCtrl() +{ + // Children all cleaned up by default view destructor. +} + +// static +void LLMultiSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata ) +{ + LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; + llassert( caller == self->mEditor ); + + self->onFocusReceived(); +} + + +void LLMultiSliderCtrl::setValue(const LLSD& value) +{ + mMultiSlider->setValue(value); + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); +} + +void LLMultiSliderCtrl::setSliderValue(const LLString& name, F32 v, BOOL from_event) +{ + mMultiSlider->setSliderValue(name, v, from_event ); + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); +} + +void LLMultiSliderCtrl::setCurSlider(const LLString& name) +{ + mMultiSlider->setCurSlider(name); + mCurValue = mMultiSlider->getCurSliderValue(); +} + +BOOL LLMultiSliderCtrl::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 = mMultiSlider->getRect(); + S32 left = rect.mLeft + delta; + left = llclamp(left, 0, rect.mRight-MULTI_SLIDERCTRL_SPACING); + rect.mLeft = left; + mMultiSlider->setRect(rect); + } + } + return res; +} + +const LLString& LLMultiSliderCtrl::addSlider() +{ + const LLString& name = mMultiSlider->addSlider(); + + // if it returns null, pass it on + if(name == LLString::null) { + return LLString::null; + } + + // otherwise, update stuff + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); + return name; +} + +const LLString& LLMultiSliderCtrl::addSlider(F32 val) +{ + const LLString& name = mMultiSlider->addSlider(val); + + // if it returns null, pass it on + if(name == LLString::null) { + return LLString::null; + } + + // otherwise, update stuff + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); + return name; +} + +void LLMultiSliderCtrl::deleteSlider(const LLString& name) +{ + mMultiSlider->deleteSlider(name); + mCurValue = mMultiSlider->getCurSliderValue(); + updateText(); +} + + +void LLMultiSliderCtrl::clear() +{ + setCurSliderValue(0.0f); + if( mEditor ) + { + mEditor->setText(LLString("")); + } + if( mTextBox ) + { + mTextBox->setText(LLString("")); + } + + // get rid of sliders + mMultiSlider->clear(); + +} + +BOOL LLMultiSliderCtrl::isMouseHeldDown() +{ + return gFocusMgr.getMouseCapture() == mMultiSlider; +} + +void LLMultiSliderCtrl::updateText() +{ + if( mEditor || mTextBox ) + { + LLLocale locale(LLLocale::USER_LOCALE); + + // Don't display very small negative values as -0.000 + F32 displayed_value = (F32)(floor(getCurSliderValue() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)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 LLMultiSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata ) +{ + LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; + llassert( caller == self->mEditor ); + + BOOL success = FALSE; + F32 val = self->mCurValue; + F32 saved_val = self->mCurValue; + + LLString text = self->mEditor->getText(); + if( LLLineEditor::postvalidateFloat( text ) ) + { + LLLocale locale(LLLocale::USER_LOCALE); + val = (F32) atof( text.c_str() ); + if( self->mMultiSlider->getMinValue() <= val && val <= self->mMultiSlider->getMaxValue() ) + { + if( self->mValidateCallback ) + { + self->setCurSliderValue( val ); // set the value temporarily so that the callback can retrieve it. + if( self->mValidateCallback( self, self->mCallbackUserData ) ) + { + success = TRUE; + } + } + else + { + self->setCurSliderValue( val ); + success = TRUE; + } + } + } + + if( success ) + { + self->onCommit(); + } + else + { + if( self->getCurSliderValue() != saved_val ) + { + self->setCurSliderValue( saved_val ); + } + self->reportInvalidData(); + } + self->updateText(); +} + +// static +void LLMultiSliderCtrl::onSliderCommit( LLUICtrl* caller, void *userdata ) +{ + LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; + //llassert( caller == self->mSlider ); + + BOOL success = FALSE; + F32 saved_val = self->mCurValue; + F32 new_val = self->mMultiSlider->getCurSliderValue(); + + if( self->mValidateCallback ) + { + self->mCurValue = new_val; // set the value temporarily so that the callback can retrieve it. + if( self->mValidateCallback( self, self->mCallbackUserData ) ) + { + success = TRUE; + } + } + else + { + self->mCurValue = new_val; + success = TRUE; + } + + if( success ) + { + self->onCommit(); + } + else + { + if( self->mCurValue != saved_val ) + { + self->setCurSliderValue( saved_val ); + } + self->reportInvalidData(); + } + self->updateText(); +} + +void LLMultiSliderCtrl::setEnabled(BOOL b) +{ + LLUICtrl::setEnabled( b ); + + if( mLabelBox ) + { + mLabelBox->setColor( b ? mTextEnabledColor : mTextDisabledColor ); + } + + mMultiSlider->setEnabled( b ); + + if( mEditor ) + { + mEditor->setEnabled( b ); + } + + if( mTextBox ) + { + mTextBox->setColor( b ? mTextEnabledColor : mTextDisabledColor ); + } +} + + +void LLMultiSliderCtrl::setTentative(BOOL b) +{ + if( mEditor ) + { + mEditor->setTentative(b); + } + LLUICtrl::setTentative(b); +} + + +void LLMultiSliderCtrl::onCommit() +{ + setTentative(FALSE); + + if( mEditor ) + { + mEditor->setTentative(FALSE); + } + + LLUICtrl::onCommit(); +} + + +void LLMultiSliderCtrl::setPrecision(S32 precision) +{ + if (precision < 0 || precision > 10) + { + llerrs << "LLMultiSliderCtrl::setPrecision - precision out of range" << llendl; + return; + } + + mPrecision = precision; + updateText(); +} + +void LLMultiSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) ) +{ + mSliderMouseDownCallback = slider_mousedown_callback; + mMultiSlider->setMouseDownCallback( LLMultiSliderCtrl::onSliderMouseDown ); +} + +// static +void LLMultiSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata) +{ + LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; + if( self->mSliderMouseDownCallback ) + { + self->mSliderMouseDownCallback( self, self->mCallbackUserData ); + } +} + + +void LLMultiSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) ) +{ + mSliderMouseUpCallback = slider_mouseup_callback; + mMultiSlider->setMouseUpCallback( LLMultiSliderCtrl::onSliderMouseUp ); +} + +// static +void LLMultiSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata) +{ + LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; + if( self->mSliderMouseUpCallback ) + { + self->mSliderMouseUpCallback( self, self->mCallbackUserData ); + } +} + +void LLMultiSliderCtrl::onTabInto() +{ + if( mEditor ) + { + mEditor->onTabInto(); + } +} + +void LLMultiSliderCtrl::reportInvalidData() +{ + make_ui_sound("UISndBadKeystroke"); +} + +//virtual +LLString LLMultiSliderCtrl::getControlName() const +{ + return mMultiSlider->getControlName(); +} + +// virtual +void LLMultiSliderCtrl::setControlName(const LLString& control_name, LLView* context) +{ + mMultiSlider->setControlName(control_name, context); +} + +// virtual +LLXMLNodePtr LLMultiSliderCtrl::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(mCurValue); + + if (mMultiSlider) + { + node->createChild("initial_val", TRUE)->setFloatValue(mMultiSlider->getInitialValue()); + node->createChild("min_val", TRUE)->setFloatValue(mMultiSlider->getMinValue()); + node->createChild("max_val", TRUE)->setFloatValue(mMultiSlider->getMaxValue()); + node->createChild("increment", TRUE)->setFloatValue(mMultiSlider->getIncrement()); + } + addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor"); + addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor"); + + return node; +} + +LLView* LLMultiSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + LLString name("multi_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); + + BOOL allow_overlap = FALSE; + node->getAttributeBOOL("allow_overlap", allow_overlap); + + BOOL draw_track = TRUE; + node->getAttributeBOOL("draw_track", draw_track); + + BOOL use_triangle = FALSE; + node->getAttributeBOOL("use_triangle", use_triangle); + + 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 max_sliders = 1; + node->getAttributeS32("max_sliders", max_sliders); + + + 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()); + } + + LLMultiSliderCtrl* slider = new LLMultiSliderCtrl(name, + rect, + label, + font, + label_width, + rect.getWidth() - text_left, + show_text, + can_edit_text, + callback, + NULL, + initial_value, + min_value, + max_value, + increment, + max_sliders, + allow_overlap, + draw_track, + use_triangle); + + slider->setPrecision(precision); + + slider->initFromXML(node, parent); + + slider->updateText(); + + return slider; +} -- cgit v1.1