PageRenderTime 35ms CodeModel.GetById 1ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llui/llmultisliderctrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 489 lines | 375 code | 72 blank | 42 comment | 49 complexity | cd64cac0c3b14f149c1eb4487e18d96c MD5 | raw file
  1/** 
  2 * @file llmultisliderctrl.cpp
  3 * @brief LLMultiSliderCtrl base class
  4 *
  5 * $LicenseInfo:firstyear=2007&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 "llmultisliderctrl.h"
 30
 31#include "llmath.h"
 32#include "llfontgl.h"
 33#include "llgl.h"
 34#include "llkeyboard.h"
 35#include "lllineeditor.h"
 36#include "llmultislider.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
 46static LLDefaultChildRegistry::Register<LLMultiSliderCtrl> r("multi_slider");
 47
 48const U32 MAX_STRING_LENGTH = 10;
 49LLMultiSliderCtrl::Params::Params()
 50:	text_width("text_width"),
 51	label_width("label_width"),
 52	show_text("show_text", true),
 53	can_edit_text("can_edit_text", false),
 54	max_sliders("max_sliders", 1),
 55	allow_overlap("allow_overlap", false),
 56	draw_track("draw_track", true),
 57	use_triangle("use_triangle", false),
 58	decimal_digits("decimal_digits", 3),
 59	text_color("text_color"),
 60	text_disabled_color("text_disabled_color"),
 61	mouse_down_callback("mouse_down_callback"),
 62	mouse_up_callback("mouse_up_callback"),
 63	sliders("slider")
 64{
 65	mouse_opaque = true;
 66}
 67 
 68LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
 69:	LLF32UICtrl(p),
 70	mLabelBox( NULL ),
 71	mEditor( NULL ),
 72	mTextBox( NULL ),
 73	mTextEnabledColor(p.text_color()),
 74	mTextDisabledColor(p.text_disabled_color())
 75{
 76	static LLUICachedControl<S32> multi_sliderctrl_spacing ("UIMultiSliderctrlSpacing", 0);
 77
 78	S32 top = getRect().getHeight();
 79	S32 bottom = 0;
 80	S32 left = 0;
 81
 82	S32 label_width = p.label_width;
 83	S32 text_width = p.text_width;
 84
 85	// Label
 86	if( !p.label().empty() )
 87	{
 88		if (p.label_width == 0)
 89		{
 90			label_width = p.font()->getWidth(p.label);
 91		}
 92		LLRect label_rect( left, top, label_width, bottom );
 93		LLTextBox::Params params;
 94		params.name("MultiSliderCtrl Label");
 95		params.rect(label_rect);
 96		params.initial_value(p.label());
 97		params.font(p.font);
 98		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
 99		addChild(mLabelBox);
100	}
101
102	S32 slider_right = getRect().getWidth();
103
104	if (p.show_text)
105	{
106		if (!p.text_width.isProvided())
107		{
108			text_width = 0;
109			// calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
110			if ( p.max_value() )
111				text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10  ( p.max_value ) ) + p.decimal_digits + 1 );
112
113			if ( p.increment < 1.0f )
114				text_width += p.font()->getWidth(std::string("."));	// (mostly) take account of decimal point in value
115
116			if ( p.min_value < 0.0f || p.max_value < 0.0f )
117				text_width += p.font()->getWidth(std::string("-"));	// (mostly) take account of minus sign 
118
119			// padding to make things look nicer
120			text_width += 8;
121		}
122		S32 text_left = getRect().getWidth() - text_width;
123
124		slider_right = text_left - multi_sliderctrl_spacing;
125
126		LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
127		if( p.can_edit_text )
128		{
129			LLLineEditor::Params params;
130			params.name("MultiSliderCtrl Editor");
131			params.rect(text_rect);
132			params.font(p.font);
133			params.max_length.bytes(MAX_STRING_LENGTH);
134			params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
135			params.prevalidate_callback(&LLTextValidate::validateFloat);
136			params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
137			mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
138			mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) );
139			// don't do this, as selecting the entire text is single clicking in some cases
140			// and double clicking in others
141			//mEditor->setSelectAllonFocusReceived(TRUE);
142			addChild(mEditor);
143		}
144		else
145		{
146			LLTextBox::Params params;
147			params.name("MultiSliderCtrl Text");
148			params.rect(text_rect);
149			params.font(p.font);
150			params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
151			mTextBox = LLUICtrlFactory::create<LLTextBox> (params);
152			addChild(mTextBox);
153		}
154	}
155
156	S32 slider_left = label_width ? label_width + multi_sliderctrl_spacing : 0;
157	LLRect slider_rect( slider_left, top, slider_right, bottom );
158	LLMultiSlider::Params params;
159	params.sliders = p.sliders;
160	params.rect(slider_rect);
161	params.commit_callback.function( LLMultiSliderCtrl::onSliderCommit );
162	params.mouse_down_callback( p.mouse_down_callback );
163	params.mouse_up_callback( p.mouse_up_callback );
164	params.initial_value(p.initial_value());
165	params.min_value(p.min_value);
166	params.max_value(p.max_value);
167	params.increment(p.increment);
168	params.max_sliders(p.max_sliders);
169	params.allow_overlap(p.allow_overlap);
170	params.draw_track(p.draw_track);
171	params.use_triangle(p.use_triangle);
172	params.control_name(p.control_name);
173	mMultiSlider = LLUICtrlFactory::create<LLMultiSlider> (params);
174	addChild( mMultiSlider );
175	mCurValue = mMultiSlider->getCurSliderValue();
176
177
178	updateText();
179}
180
181LLMultiSliderCtrl::~LLMultiSliderCtrl()
182{
183	// Children all cleaned up by default view destructor.
184}
185
186// static
187void LLMultiSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
188{
189	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
190	llassert( caller == self->mEditor );
191
192	self->onFocusReceived();
193}
194
195
196void LLMultiSliderCtrl::setValue(const LLSD& value)
197{
198	mMultiSlider->setValue(value);
199	mCurValue = mMultiSlider->getCurSliderValue();
200	updateText();
201}
202
203void LLMultiSliderCtrl::setSliderValue(const std::string& name, F32 v, BOOL from_event)
204{
205	mMultiSlider->setSliderValue(name, v, from_event );
206	mCurValue = mMultiSlider->getCurSliderValue();
207	updateText();
208}
209
210void LLMultiSliderCtrl::setCurSlider(const std::string& name)
211{
212	mMultiSlider->setCurSlider(name);
213	mCurValue = mMultiSlider->getCurSliderValue();
214}
215
216BOOL LLMultiSliderCtrl::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 && mLabelWidth == 0)
223		{
224			S32 label_width = mFont->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 = mMultiSlider->getRect();
232			S32 left = rect.mLeft + delta;
233			static LLUICachedControl<S32> multi_slider_ctrl_spacing ("UIMultiSliderctrlSpacing", 0);
234			left = llclamp(left, 0, rect.mRight - multi_slider_ctrl_spacing);
235			rect.mLeft = left;
236			mMultiSlider->setRect(rect);
237		}
238	}
239	return res;
240}
241
242const std::string& LLMultiSliderCtrl::addSlider()
243{
244	const std::string& name = mMultiSlider->addSlider();
245	
246	// if it returns null, pass it on
247	if(name == LLStringUtil::null) {
248		return LLStringUtil::null;
249	}
250
251	// otherwise, update stuff
252	mCurValue = mMultiSlider->getCurSliderValue();
253	updateText();
254	return name;
255}
256
257const std::string& LLMultiSliderCtrl::addSlider(F32 val)
258{
259	const std::string& name = mMultiSlider->addSlider(val);
260
261	// if it returns null, pass it on
262	if(name == LLStringUtil::null) {
263		return LLStringUtil::null;
264	}
265
266	// otherwise, update stuff
267	mCurValue = mMultiSlider->getCurSliderValue();
268	updateText();
269	return name;
270}
271
272void LLMultiSliderCtrl::deleteSlider(const std::string& name)
273{
274	mMultiSlider->deleteSlider(name);
275	mCurValue = mMultiSlider->getCurSliderValue();
276	updateText();
277}
278
279
280void LLMultiSliderCtrl::clear()
281{
282	setCurSliderValue(0.0f);
283	if( mEditor )
284	{
285		mEditor->setText(std::string(""));
286	}
287	if( mTextBox )
288	{
289		mTextBox->setText(std::string(""));
290	}
291
292	// get rid of sliders
293	mMultiSlider->clear();
294
295}
296
297BOOL LLMultiSliderCtrl::isMouseHeldDown()
298{
299	return gFocusMgr.getMouseCapture() == mMultiSlider;
300}
301
302void LLMultiSliderCtrl::updateText()
303{
304	if( mEditor || mTextBox )
305	{
306		LLLocale locale(LLLocale::USER_LOCALE);
307
308		// Don't display very small negative values as -0.000
309		F32 displayed_value = (F32)(floor(getCurSliderValue() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision));
310
311		std::string format = llformat("%%.%df", mPrecision);
312		std::string text = llformat(format.c_str(), displayed_value);
313		if( mEditor )
314		{
315			mEditor->setText( text );
316		}
317		else
318		{
319			mTextBox->setText( text );
320		}
321	}
322}
323
324// static
325void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata)
326{
327	llassert(ctrl);
328	if (!ctrl)
329		return;
330
331	LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent());
332	llassert(self);
333	if (!self) // cast failed - wrong type! :O
334		return;
335	
336	BOOL success = FALSE;
337	F32 val = self->mCurValue;
338	F32 saved_val = self->mCurValue;
339
340	std::string text = self->mEditor->getText();
341	if( LLLineEditor::postvalidateFloat( text ) )
342	{
343		LLLocale locale(LLLocale::USER_LOCALE);
344		val = (F32) atof( text.c_str() );
345		if( self->mMultiSlider->getMinValue() <= val && val <= self->mMultiSlider->getMaxValue() )
346		{
347			self->setCurSliderValue( val );  // set the value temporarily so that the callback can retrieve it.
348			if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) )
349			{
350				success = TRUE;
351			}
352		}
353	}
354
355	if( success )
356	{
357		self->onCommit();
358	}
359	else
360	{
361		if( self->getCurSliderValue() != saved_val )
362		{
363			self->setCurSliderValue( saved_val );
364		}
365		self->reportInvalidData();		
366	}
367	self->updateText();
368}
369
370// static
371void LLMultiSliderCtrl::onSliderCommit(LLUICtrl* ctrl, const LLSD& userdata)
372{
373	LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent());
374	if (!self)
375		return;
376	
377	BOOL success = FALSE;
378	F32 saved_val = self->mCurValue;
379	F32 new_val = self->mMultiSlider->getCurSliderValue();
380
381	self->mCurValue = new_val;  // set the value temporarily so that the callback can retrieve it.
382	if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) )
383	{
384		success = TRUE;
385	}
386
387	if( success )
388	{
389		self->onCommit();
390	}
391	else
392	{
393		if( self->mCurValue != saved_val )
394		{
395			self->setCurSliderValue( saved_val );
396		}
397		self->reportInvalidData();		
398	}
399	self->updateText();
400}
401
402void LLMultiSliderCtrl::setEnabled(BOOL b)
403{
404	LLF32UICtrl::setEnabled( b );
405
406	if( mLabelBox )
407	{
408		mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
409	}
410
411	mMultiSlider->setEnabled( b );
412
413	if( mEditor )
414	{
415		mEditor->setEnabled( b );
416	}
417
418	if( mTextBox )
419	{
420		mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
421	}
422}
423
424
425void LLMultiSliderCtrl::setTentative(BOOL b)
426{
427	if( mEditor )
428	{
429		mEditor->setTentative(b);
430	}
431	LLF32UICtrl::setTentative(b);
432}
433
434
435void LLMultiSliderCtrl::onCommit()
436{
437	setTentative(FALSE);
438
439	if( mEditor )
440	{
441		mEditor->setTentative(FALSE);
442	}
443
444	setControlValue(getValueF32());
445	LLF32UICtrl::onCommit();
446}
447
448
449void LLMultiSliderCtrl::setPrecision(S32 precision)
450{
451	if (precision < 0 || precision > 10)
452	{
453		llerrs << "LLMultiSliderCtrl::setPrecision - precision out of range" << llendl;
454		return;
455	}
456
457	mPrecision = precision;
458	updateText();
459}
460
461boost::signals2::connection LLMultiSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
462{
463	return mMultiSlider->setMouseDownCallback( cb );
464}
465
466boost::signals2::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
467{
468	return mMultiSlider->setMouseUpCallback( cb );
469}
470
471void LLMultiSliderCtrl::onTabInto()
472{
473	if( mEditor )
474	{
475		mEditor->onTabInto(); 
476	}
477}
478
479void LLMultiSliderCtrl::reportInvalidData()
480{
481	make_ui_sound("UISndBadKeystroke");
482}
483
484// virtual
485void LLMultiSliderCtrl::setControlName(const std::string& control_name, LLView* context)
486{
487	mMultiSlider->setControlName(control_name, context);
488}
489