llsliderctrl.cpp

Go to the documentation of this file.
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         // Label
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                         // don't do this, as selecting the entire text is single clicking in some cases
00132                         // and double clicking in others
00133                         //mEditor->setSelectAllonFocusReceived(TRUE);
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 // static
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                 // Don't display very small negative values as -0.000
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 // static
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 );  // set the value temporarily so that the callback can retrieve it.
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 // static
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;  // set the value temporarily so that the callback can retrieve it.
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 // static
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 // static
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 // virtual
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         // TomY TODO: Do we really want to export the transient state of the slider?
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         // HACK: Font might not be specified.
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                 // calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
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(".");       // (mostly) take account of decimal point in value
00507 
00508                 if ( min_value < 0.0f || max_value < 0.0f )
00509                         text_left += font->getWidth("-");       // (mostly) take account of minus sign 
00510 
00511                 // padding to make things look nicer
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 }

Generated on Fri May 16 08:32:58 2008 for SecondLife by  doxygen 1.5.5