PageRenderTime 69ms CodeModel.GetById 1ms app.highlight 63ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llsliderctrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 436 lines | 338 code | 60 blank | 38 comment | 57 complexity | e95161518ac6266b60a26daf426fc88c MD5 | raw file
  1/** 
  2 * @file llsliderctrl.cpp
  3 * @brief LLSliderCtrl base class
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28
 29#include "llsliderctrl.h"
 30
 31#include "llmath.h"
 32#include "llfontgl.h"
 33#include "llgl.h"
 34#include "llkeyboard.h"
 35#include "lllineeditor.h"
 36#include "llslider.h"
 37#include "llstring.h"
 38#include "lltextbox.h"
 39#include "llui.h"
 40#include "lluiconstants.h"
 41#include "llcontrol.h"
 42#include "llfocusmgr.h"
 43#include "llresmgr.h"
 44#include "lluictrlfactory.h"
 45
 46const U32 MAX_STRING_LENGTH = 10;
 47
 48static LLDefaultChildRegistry::Register<LLSliderCtrl> r("slider");
 49
 50LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)
 51:	LLF32UICtrl(p),
 52	mLabelBox( NULL ),
 53	mEditor( NULL ),
 54	mTextBox( NULL ),
 55	mFont(p.font),
 56	mShowText(p.show_text),
 57	mCanEditText(p.can_edit_text),
 58	mPrecision(p.decimal_digits),
 59	mTextEnabledColor(p.text_color()),
 60	mTextDisabledColor(p.text_disabled_color()),
 61	mLabelWidth(p.label_width)
 62{
 63	S32 top = getRect().getHeight();
 64	S32 bottom = 0;
 65	S32 left = 0;
 66
 67	S32 label_width = p.label_width;
 68	S32 text_width = p.text_width;
 69
 70	// Label
 71	if( !p.label().empty() )
 72	{
 73		if (!p.label_width.isProvided())
 74		{
 75			label_width = p.font()->getWidth(p.label);
 76		}
 77		LLRect label_rect( left, top, label_width, bottom );
 78		LLTextBox::Params params(p.slider_label);
 79		if (!params.rect.isProvided())
 80		{
 81			params.rect = label_rect;
 82		}
 83		if (!params.font.isProvided())
 84		{
 85			params.font = p.font;
 86		}
 87		params.initial_value(p.label());
 88		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
 89		addChild(mLabelBox);
 90		mLabelFont = params.font();
 91	}
 92
 93	if (p.show_text && !p.text_width.isProvided())
 94	{
 95		// calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
 96		if ( p.max_value )
 97			text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10  ( p.max_value ) ) + p.decimal_digits + 1 );
 98
 99		if ( p.increment < 1.0f )
100			text_width += p.font()->getWidth(std::string("."));	// (mostly) take account of decimal point in value
101
102		if ( p.min_value < 0.0f || p.max_value < 0.0f )
103			text_width += p.font()->getWidth(std::string("-"));	// (mostly) take account of minus sign 
104
105		// padding to make things look nicer
106		text_width += 8;
107	}
108
109
110	S32 text_left = getRect().getWidth() - text_width;
111	static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0);
112
113	S32 slider_right = getRect().getWidth();
114	if( p.show_text )
115	{
116		slider_right = text_left - sliderctrl_spacing;
117	}
118
119	S32 slider_left = label_width ? label_width + sliderctrl_spacing : 0;
120	LLSlider::Params slider_p(p.slider_bar);
121	slider_p.name("slider_bar");
122	if (!slider_p.rect.isProvided())
123	{
124		slider_p.rect = LLRect(slider_left,top,slider_right,bottom);
125	}
126	if (!slider_p.initial_value.isProvided())
127	{
128		slider_p.initial_value = p.initial_value().asReal();
129	}
130	if (!slider_p.min_value.isProvided())
131	{
132		slider_p.min_value = p.min_value;
133	}
134	if (!slider_p.max_value.isProvided())
135	{
136		slider_p.max_value = p.max_value;
137	}
138	if (!slider_p.increment.isProvided())
139	{
140		slider_p.increment = p.increment;
141	}
142	if (!slider_p.orientation.isProvided())
143	{
144		slider_p.orientation = p.orientation;
145	}
146	
147	slider_p.commit_callback.function = &LLSliderCtrl::onSliderCommit;
148	slider_p.control_name = p.control_name;
149	slider_p.mouse_down_callback( p.mouse_down_callback );
150	slider_p.mouse_up_callback( p.mouse_up_callback );
151	mSlider = LLUICtrlFactory::create<LLSlider> (slider_p);
152
153	addChild( mSlider );
154	
155	if( p.show_text() )
156	{
157		LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
158		if( p.can_edit_text() )
159		{
160			LLLineEditor::Params line_p(p.value_editor);
161			if (!line_p.rect.isProvided())
162			{
163				line_p.rect = text_rect;
164			}
165			if (!line_p.font.isProvided())
166			{
167				line_p.font = p.font;
168			}
169			
170			line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit);
171			line_p.prevalidate_callback(&LLTextValidate::validateFloat);
172			mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p);
173
174			mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this ));
175			// don't do this, as selecting the entire text is single clicking in some cases
176			// and double clicking in others
177			//mEditor->setSelectAllonFocusReceived(TRUE);
178			addChild(mEditor);
179		}
180		else
181		{
182			LLTextBox::Params text_p(p.value_text);
183			if (!text_p.rect.isProvided())
184			{
185				text_p.rect = text_rect;
186			}
187			if (!text_p.font.isProvided())
188			{
189				text_p.font = p.font;
190			}
191			mTextBox = LLUICtrlFactory::create<LLTextBox>(text_p);
192			addChild(mTextBox);
193		}
194	}
195
196	updateText();
197}
198
199// static
200void LLSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
201{
202	LLSliderCtrl* self = (LLSliderCtrl*) userdata;
203	llassert( caller == self->mEditor );
204
205	self->onFocusReceived();
206}
207
208
209void LLSliderCtrl::setValue(F32 v, BOOL from_event)
210{
211	mSlider->setValue( v, from_event );
212	mValue = mSlider->getValueF32();
213	updateText();
214}
215
216BOOL LLSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text )
217{
218	BOOL res = FALSE;
219	if (mLabelBox)
220	{
221		res = mLabelBox->setTextArg(key, text);
222		if (res && mLabelFont && mLabelWidth == 0)
223		{
224			S32 label_width = mLabelFont->getWidth(mLabelBox->getText());
225			LLRect rect = mLabelBox->getRect();
226			S32 prev_right = rect.mRight;
227			rect.mRight = rect.mLeft + label_width;
228			mLabelBox->setRect(rect);
229				
230			S32 delta = rect.mRight - prev_right;
231			rect = mSlider->getRect();
232			S32 left = rect.mLeft + delta;
233			static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0);
234			left = llclamp(left, 0, rect.mRight - sliderctrl_spacing);
235			rect.mLeft = left;
236			mSlider->setRect(rect);
237		}
238	}
239	return res;
240}
241
242void LLSliderCtrl::clear()
243{
244	setValue(0.0f);
245	if( mEditor )
246	{
247		mEditor->setText( LLStringUtil::null );
248	}
249	if( mTextBox )
250	{
251		mTextBox->setText( LLStringUtil::null );
252	}
253
254}
255
256void LLSliderCtrl::updateText()
257{
258	if( mEditor || mTextBox )
259	{
260		LLLocale locale(LLLocale::USER_LOCALE);
261
262		// Don't display very small negative values as -0.000
263		F32 displayed_value = (F32)(floor(getValueF32() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision));
264
265		std::string format = llformat("%%.%df", mPrecision);
266		std::string text = llformat(format.c_str(), displayed_value);
267		if( mEditor )
268		{
269			// Setting editor text here to "" before using actual text is here because if text which
270			// is set is the same as the one which is actually typed into lineeditor, LLLineEditor::setText()
271			// will exit at it's beginning, so text for revert on escape won't be saved. (EXT-8536)
272			mEditor->setText( LLStringUtil::null );
273			mEditor->setText( text );
274		}
275		else
276		{
277			mTextBox->setText( text );
278		}
279	}
280}
281
282// static
283void LLSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata )
284{
285	LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent());
286	if (!self)
287		return;
288
289	BOOL success = FALSE;
290	F32 val = self->mValue;
291	F32 saved_val = self->mValue;
292
293	std::string text = self->mEditor->getText();
294	if( LLLineEditor::postvalidateFloat( text ) )
295	{
296		LLLocale locale(LLLocale::USER_LOCALE);
297		val = (F32) atof( text.c_str() );
298		if( self->mSlider->getMinValue() <= val && val <= self->mSlider->getMaxValue() )
299		{
300			self->setValue( val );  // set the value temporarily so that the callback can retrieve it.
301			if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) )
302			{
303				success = TRUE;
304			}
305		}
306	}
307
308	if( success )
309	{
310		self->onCommit();
311	}
312	else
313	{
314		if( self->getValueF32() != saved_val )
315		{
316			self->setValue( saved_val );
317		}
318		self->reportInvalidData();		
319	}
320	self->updateText();
321}
322
323// static
324void LLSliderCtrl::onSliderCommit( LLUICtrl* ctrl, const LLSD& userdata )
325{
326	LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent());
327	if (!self)
328		return;
329
330	BOOL success = FALSE;
331	F32 saved_val = self->mValue;
332	F32 new_val = self->mSlider->getValueF32();
333
334	self->mValue = new_val;  // set the value temporarily so that the callback can retrieve it.
335	if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) )
336	{
337		success = TRUE;
338	}
339
340	if( success )
341	{
342		self->onCommit();
343	}
344	else
345	{
346		if( self->mValue != saved_val )
347		{
348			self->setValue( saved_val );
349		}
350		self->reportInvalidData();		
351	}
352	self->updateText();
353}
354
355void LLSliderCtrl::setEnabled(BOOL b)
356{
357	LLView::setEnabled( b );
358
359	if( mLabelBox )
360	{
361		mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
362	}
363
364	mSlider->setEnabled( b );
365
366	if( mEditor )
367	{
368		mEditor->setEnabled( b );
369	}
370
371	if( mTextBox )
372	{
373		mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
374	}
375}
376
377
378void LLSliderCtrl::setTentative(BOOL b)
379{
380	if( mEditor )
381	{
382		mEditor->setTentative(b);
383	}
384	LLF32UICtrl::setTentative(b);
385}
386
387
388void LLSliderCtrl::onCommit()
389{
390	setTentative(FALSE);
391
392	if( mEditor )
393	{
394		mEditor->setTentative(FALSE);
395	}
396	
397	setControlValue(getValueF32());
398	LLF32UICtrl::onCommit();
399}
400
401
402void LLSliderCtrl::setPrecision(S32 precision)
403{
404	if (precision < 0 || precision > 10)
405	{
406		llerrs << "LLSliderCtrl::setPrecision - precision out of range" << llendl;
407		return;
408	}
409
410	mPrecision = precision;
411	updateText();
412}
413
414boost::signals2::connection LLSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
415{
416	return mSlider->setMouseDownCallback( cb );
417}
418
419boost::signals2::connection LLSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
420{
421	return mSlider->setMouseUpCallback( cb );
422}
423
424void LLSliderCtrl::onTabInto()
425{
426	if( mEditor )
427	{
428		mEditor->onTabInto(); 
429	}
430}
431
432void LLSliderCtrl::reportInvalidData()
433{
434	make_ui_sound("UISndBadKeystroke");
435}
436