summaryrefslogtreecommitdiff
path: root/indra/llui/llsliderctrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/llsliderctrl.cpp')
-rw-r--r--indra/llui/llsliderctrl.cpp538
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;
+}