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