summaryrefslogtreecommitdiff
path: root/indra/llui/llmultisliderctrl.cpp
diff options
context:
space:
mode:
authorBrad Kittenbrink <brad@lindenlab.com>2008-02-27 18:58:14 +0000
committerBrad Kittenbrink <brad@lindenlab.com>2008-02-27 18:58:14 +0000
commit6d52efe452aa8469e0343da1c7d108f3f52ab651 (patch)
treea87be48e9840d7fc1f7ee514d7c7f994e71fdb3c /indra/llui/llmultisliderctrl.cpp
parent6027ad2630b8650cabcf00628ee9b0d25bedd67f (diff)
Merge of windlight into release (QAR-286). This includes all changes in
windlight14 which have passed QA (up through r79932). svn merge -r 80831:80833 svn+ssh://svn.lindenlab.com/svn/linden/branches/merge_windlight14_r80620
Diffstat (limited to 'indra/llui/llmultisliderctrl.cpp')
-rw-r--r--indra/llui/llmultisliderctrl.cpp634
1 files changed, 634 insertions, 0 deletions
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
new file mode 100644
index 0000000000..6f921a4e5e
--- /dev/null
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -0,0 +1,634 @@
+/**
+ * @file llmultisliderctrl.cpp
+ * @brief LLMultiSliderCtrl base class
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ *
+ * Copyright (c) 2007-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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;
+}