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