00001
00032 #include "linden_common.h"
00033
00034 #include "llsliderctrl.h"
00035
00036 #include "audioengine.h"
00037 #include "sound_ids.h"
00038
00039 #include "llmath.h"
00040 #include "llfontgl.h"
00041 #include "llgl.h"
00042 #include "llkeyboard.h"
00043 #include "lllineeditor.h"
00044 #include "llslider.h"
00045 #include "llstring.h"
00046 #include "lltextbox.h"
00047 #include "llui.h"
00048 #include "lluiconstants.h"
00049 #include "llcontrol.h"
00050 #include "llfocusmgr.h"
00051 #include "llresmgr.h"
00052
00053 const U32 MAX_STRING_LENGTH = 10;
00054
00055 static LLRegisterWidget<LLSliderCtrl> r("slider");
00056
00057 LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect,
00058 const LLString& label,
00059 const LLFontGL* font,
00060 S32 label_width,
00061 S32 text_left,
00062 BOOL show_text,
00063 BOOL can_edit_text,
00064 BOOL volume,
00065 void (*commit_callback)(LLUICtrl*, void*),
00066 void* callback_user_data,
00067 F32 initial_value, F32 min_value, F32 max_value, F32 increment,
00068 const LLString& control_which)
00069 : LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data ),
00070 mFont(font),
00071 mShowText( show_text ),
00072 mCanEditText( can_edit_text ),
00073 mVolumeSlider( volume ),
00074 mPrecision( 3 ),
00075 mLabelBox( NULL ),
00076 mLabelWidth( label_width ),
00077 mValue( initial_value ),
00078 mEditor( NULL ),
00079 mTextBox( NULL ),
00080 mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
00081 mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
00082 mSliderMouseUpCallback( NULL ),
00083 mSliderMouseDownCallback( NULL )
00084 {
00085 S32 top = getRect().getHeight();
00086 S32 bottom = 0;
00087 S32 left = 0;
00088
00089
00090 if( !label.empty() )
00091 {
00092 if (label_width == 0)
00093 {
00094 label_width = font->getWidth(label);
00095 }
00096 LLRect label_rect( left, top, label_width, bottom );
00097 mLabelBox = new LLTextBox( "SliderCtrl Label", label_rect, label.c_str(), font );
00098 addChild(mLabelBox);
00099 }
00100
00101 S32 slider_right = getRect().getWidth();
00102 if( show_text )
00103 {
00104 slider_right = text_left - SLIDERCTRL_SPACING;
00105 }
00106
00107 S32 slider_left = label_width ? label_width + SLIDERCTRL_SPACING : 0;
00108 LLRect slider_rect( slider_left, top, slider_right, bottom );
00109 mSlider = new LLSlider(
00110 "slider",
00111 slider_rect,
00112 LLSliderCtrl::onSliderCommit, this,
00113 initial_value, min_value, max_value, increment, volume,
00114 control_which );
00115 addChild( mSlider );
00116
00117 if( show_text )
00118 {
00119 LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
00120 if( can_edit_text )
00121 {
00122 mEditor = new LLLineEditor( "SliderCtrl Editor", text_rect,
00123 "", font,
00124 MAX_STRING_LENGTH,
00125 &LLSliderCtrl::onEditorCommit, NULL, NULL, this,
00126 &LLLineEditor::prevalidateFloat );
00127 mEditor->setFollowsLeft();
00128 mEditor->setFollowsBottom();
00129 mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus, this );
00130 mEditor->setIgnoreTab(TRUE);
00131
00132
00133
00134 addChild(mEditor);
00135 }
00136 else
00137 {
00138 mTextBox = new LLTextBox( "SliderCtrl Text", text_rect, "", font);
00139 mTextBox->setFollowsLeft();
00140 mTextBox->setFollowsBottom();
00141 addChild(mTextBox);
00142 }
00143 }
00144
00145 updateText();
00146 }
00147
00148
00149
00150 void LLSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
00151 {
00152 LLSliderCtrl* self = (LLSliderCtrl*) userdata;
00153 llassert( caller == self->mEditor );
00154
00155 self->onFocusReceived();
00156 }
00157
00158
00159 void LLSliderCtrl::setValue(F32 v, BOOL from_event)
00160 {
00161 mSlider->setValue( v, from_event );
00162 mValue = mSlider->getValueF32();
00163 updateText();
00164 }
00165
00166 BOOL LLSliderCtrl::setLabelArg( const LLString& key, const LLStringExplicit& text )
00167 {
00168 BOOL res = FALSE;
00169 if (mLabelBox)
00170 {
00171 res = mLabelBox->setTextArg(key, text);
00172 if (res && mLabelWidth == 0)
00173 {
00174 S32 label_width = mFont->getWidth(mLabelBox->getText());
00175 LLRect rect = mLabelBox->getRect();
00176 S32 prev_right = rect.mRight;
00177 rect.mRight = rect.mLeft + label_width;
00178 mLabelBox->setRect(rect);
00179
00180 S32 delta = rect.mRight - prev_right;
00181 rect = mSlider->getRect();
00182 S32 left = rect.mLeft + delta;
00183 left = llclamp(left, 0, rect.mRight-SLIDERCTRL_SPACING);
00184 rect.mLeft = left;
00185 mSlider->setRect(rect);
00186 }
00187 }
00188 return res;
00189 }
00190
00191 void LLSliderCtrl::clear()
00192 {
00193 setValue(0.0f);
00194 if( mEditor )
00195 {
00196 mEditor->setText( LLString::null );
00197 }
00198 if( mTextBox )
00199 {
00200 mTextBox->setText( LLString::null );
00201 }
00202
00203 }
00204
00205 void LLSliderCtrl::updateText()
00206 {
00207 if( mEditor || mTextBox )
00208 {
00209 LLLocale locale(LLLocale::USER_LOCALE);
00210
00211
00212 F32 displayed_value = (F32)(floor(getValueF32() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision));
00213
00214 LLString format = llformat("%%.%df", mPrecision);
00215 LLString text = llformat(format.c_str(), displayed_value);
00216 if( mEditor )
00217 {
00218 mEditor->setText( text );
00219 }
00220 else
00221 {
00222 mTextBox->setText( text );
00223 }
00224 }
00225 }
00226
00227
00228 void LLSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
00229 {
00230 LLSliderCtrl* self = (LLSliderCtrl*) userdata;
00231 llassert( caller == self->mEditor );
00232
00233 BOOL success = FALSE;
00234 F32 val = self->mValue;
00235 F32 saved_val = self->mValue;
00236
00237 LLString text = self->mEditor->getText();
00238 if( LLLineEditor::postvalidateFloat( text ) )
00239 {
00240 LLLocale locale(LLLocale::USER_LOCALE);
00241 val = (F32) atof( text.c_str() );
00242 if( self->mSlider->getMinValue() <= val && val <= self->mSlider->getMaxValue() )
00243 {
00244 if( self->mValidateCallback )
00245 {
00246 self->setValue( val );
00247 if( self->mValidateCallback( self, self->mCallbackUserData ) )
00248 {
00249 success = TRUE;
00250 }
00251 }
00252 else
00253 {
00254 self->setValue( val );
00255 success = TRUE;
00256 }
00257 }
00258 }
00259
00260 if( success )
00261 {
00262 self->onCommit();
00263 }
00264 else
00265 {
00266 if( self->getValueF32() != saved_val )
00267 {
00268 self->setValue( saved_val );
00269 }
00270 self->reportInvalidData();
00271 }
00272 self->updateText();
00273 }
00274
00275
00276 void LLSliderCtrl::onSliderCommit( LLUICtrl* caller, void *userdata )
00277 {
00278 LLSliderCtrl* self = (LLSliderCtrl*) userdata;
00279 llassert( caller == self->mSlider );
00280
00281 BOOL success = FALSE;
00282 F32 saved_val = self->mValue;
00283 F32 new_val = self->mSlider->getValueF32();
00284
00285 if( self->mValidateCallback )
00286 {
00287 self->mValue = new_val;
00288 if( self->mValidateCallback( self, self->mCallbackUserData ) )
00289 {
00290 success = TRUE;
00291 }
00292 }
00293 else
00294 {
00295 self->mValue = new_val;
00296 success = TRUE;
00297 }
00298
00299 if( success )
00300 {
00301 self->onCommit();
00302 }
00303 else
00304 {
00305 if( self->mValue != saved_val )
00306 {
00307 self->setValue( saved_val );
00308 }
00309 self->reportInvalidData();
00310 }
00311 self->updateText();
00312 }
00313
00314 void LLSliderCtrl::setEnabled(BOOL b)
00315 {
00316 LLView::setEnabled( b );
00317
00318 if( mLabelBox )
00319 {
00320 mLabelBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
00321 }
00322
00323 mSlider->setEnabled( b );
00324
00325 if( mEditor )
00326 {
00327 mEditor->setEnabled( b );
00328 }
00329
00330 if( mTextBox )
00331 {
00332 mTextBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
00333 }
00334 }
00335
00336
00337 void LLSliderCtrl::setTentative(BOOL b)
00338 {
00339 if( mEditor )
00340 {
00341 mEditor->setTentative(b);
00342 }
00343 LLUICtrl::setTentative(b);
00344 }
00345
00346
00347 void LLSliderCtrl::onCommit()
00348 {
00349 setTentative(FALSE);
00350
00351 if( mEditor )
00352 {
00353 mEditor->setTentative(FALSE);
00354 }
00355
00356 LLUICtrl::onCommit();
00357 }
00358
00359
00360 void LLSliderCtrl::setPrecision(S32 precision)
00361 {
00362 if (precision < 0 || precision > 10)
00363 {
00364 llerrs << "LLSliderCtrl::setPrecision - precision out of range" << llendl;
00365 return;
00366 }
00367
00368 mPrecision = precision;
00369 updateText();
00370 }
00371
00372 void LLSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) )
00373 {
00374 mSliderMouseDownCallback = slider_mousedown_callback;
00375 mSlider->setMouseDownCallback( LLSliderCtrl::onSliderMouseDown );
00376 }
00377
00378
00379 void LLSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
00380 {
00381 LLSliderCtrl* self = (LLSliderCtrl*) userdata;
00382 if( self->mSliderMouseDownCallback )
00383 {
00384 self->mSliderMouseDownCallback( self, self->mCallbackUserData );
00385 }
00386 }
00387
00388
00389 void LLSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) )
00390 {
00391 mSliderMouseUpCallback = slider_mouseup_callback;
00392 mSlider->setMouseUpCallback( LLSliderCtrl::onSliderMouseUp );
00393 }
00394
00395
00396 void LLSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata)
00397 {
00398 LLSliderCtrl* self = (LLSliderCtrl*) userdata;
00399 if( self->mSliderMouseUpCallback )
00400 {
00401 self->mSliderMouseUpCallback( self, self->mCallbackUserData );
00402 }
00403 }
00404
00405 void LLSliderCtrl::onTabInto()
00406 {
00407 if( mEditor )
00408 {
00409 mEditor->onTabInto();
00410 }
00411 }
00412
00413 void LLSliderCtrl::reportInvalidData()
00414 {
00415 make_ui_sound("UISndBadKeystroke");
00416 }
00417
00418
00419 LLXMLNodePtr LLSliderCtrl::getXML(bool save_children) const
00420 {
00421 LLXMLNodePtr node = LLUICtrl::getXML();
00422
00423 node->createChild("show_text", TRUE)->setBoolValue(mShowText);
00424
00425 node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText);
00426
00427 node->createChild("volume", TRUE)->setBoolValue(mVolumeSlider);
00428
00429 node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision);
00430
00431 if (mLabelBox)
00432 {
00433 node->createChild("label", TRUE)->setStringValue(mLabelBox->getText());
00434 }
00435
00436
00437 node->createChild("value", TRUE)->setFloatValue(mValue);
00438
00439 if (mSlider)
00440 {
00441 node->createChild("initial_val", TRUE)->setFloatValue(mSlider->getInitialValue());
00442 node->createChild("min_val", TRUE)->setFloatValue(mSlider->getMinValue());
00443 node->createChild("max_val", TRUE)->setFloatValue(mSlider->getMaxValue());
00444 node->createChild("increment", TRUE)->setFloatValue(mSlider->getIncrement());
00445 }
00446 addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor");
00447 addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor");
00448
00449 return node;
00450 }
00451
00452 LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
00453 {
00454 LLString name("slider");
00455 node->getAttributeString("name", name);
00456
00457 LLString label;
00458 node->getAttributeString("label", label);
00459
00460 LLRect rect;
00461 createRect(node, rect, parent, LLRect());
00462
00463 LLFontGL* font = LLView::selectFont(node);
00464
00465
00466 if (!font)
00467 {
00468 font = LLFontGL::sSansSerifSmall;
00469 }
00470
00471 S32 label_width = 0;
00472 node->getAttributeS32("label_width", label_width);
00473
00474 BOOL show_text = TRUE;
00475 node->getAttributeBOOL("show_text", show_text);
00476
00477 BOOL can_edit_text = FALSE;
00478 node->getAttributeBOOL("can_edit_text", can_edit_text);
00479
00480 BOOL volume = FALSE;
00481 node->getAttributeBOOL("volume", volume);
00482
00483 F32 initial_value = 0.f;
00484 node->getAttributeF32("initial_val", initial_value);
00485
00486 F32 min_value = 0.f;
00487 node->getAttributeF32("min_val", min_value);
00488
00489 F32 max_value = 1.f;
00490 node->getAttributeF32("max_val", max_value);
00491
00492 F32 increment = 0.1f;
00493 node->getAttributeF32("increment", increment);
00494
00495 U32 precision = 3;
00496 node->getAttributeU32("decimal_digits", precision);
00497
00498 S32 text_left = 0;
00499 if (show_text)
00500 {
00501
00502 if ( max_value )
00503 text_left = font->getWidth("0") * ( static_cast < S32 > ( log10 ( max_value ) ) + precision + 1 );
00504
00505 if ( increment < 1.0f )
00506 text_left += font->getWidth(".");
00507
00508 if ( min_value < 0.0f || max_value < 0.0f )
00509 text_left += font->getWidth("-");
00510
00511
00512 text_left += 8;
00513 }
00514
00515 LLUICtrlCallback callback = NULL;
00516
00517 if (label.empty())
00518 {
00519 label.assign(node->getTextContents());
00520 }
00521
00522 LLSliderCtrl* slider = new LLSliderCtrl(name,
00523 rect,
00524 label,
00525 font,
00526 label_width,
00527 rect.getWidth() - text_left,
00528 show_text,
00529 can_edit_text,
00530 volume,
00531 callback,
00532 NULL,
00533 initial_value,
00534 min_value,
00535 max_value,
00536 increment);
00537
00538 slider->setPrecision(precision);
00539
00540 slider->initFromXML(node, parent);
00541
00542 slider->updateText();
00543
00544 return slider;
00545 }