diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/llsliderctrl.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llui/llsliderctrl.cpp')
-rw-r--r-- | linden/indra/llui/llsliderctrl.cpp | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/linden/indra/llui/llsliderctrl.cpp b/linden/indra/llui/llsliderctrl.cpp new file mode 100644 index 0000000..ca8f3ad --- /dev/null +++ b/linden/indra/llui/llsliderctrl.cpp | |||
@@ -0,0 +1,557 @@ | |||
1 | /** | ||
2 | * @file llsliderctrl.cpp | ||
3 | * @brief LLSliderCtrl base class | ||
4 | * | ||
5 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include "llsliderctrl.h" | ||
31 | |||
32 | #include "audioengine.h" | ||
33 | #include "sound_ids.h" | ||
34 | |||
35 | #include "llmath.h" | ||
36 | #include "llfontgl.h" | ||
37 | #include "llgl.h" | ||
38 | #include "llkeyboard.h" | ||
39 | #include "lllineeditor.h" | ||
40 | #include "llslider.h" | ||
41 | #include "llstring.h" | ||
42 | #include "lltextbox.h" | ||
43 | #include "llui.h" | ||
44 | #include "lluiconstants.h" | ||
45 | #include "llcontrol.h" | ||
46 | #include "llfocusmgr.h" | ||
47 | #include "llresmgr.h" | ||
48 | |||
49 | const U32 MAX_STRING_LENGTH = 10; | ||
50 | |||
51 | |||
52 | LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect, | ||
53 | const LLString& label, | ||
54 | const LLFontGL* font, | ||
55 | S32 label_width, | ||
56 | S32 text_left, | ||
57 | BOOL show_text, | ||
58 | BOOL can_edit_text, | ||
59 | void (*commit_callback)(LLUICtrl*, void*), | ||
60 | void* callback_user_data, | ||
61 | F32 initial_value, F32 min_value, F32 max_value, F32 increment, | ||
62 | const LLString& control_which) | ||
63 | : LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data ), | ||
64 | mFont(font), | ||
65 | mShowText( show_text ), | ||
66 | mCanEditText( can_edit_text ), | ||
67 | mPrecision( 3 ), | ||
68 | mLabelBox( NULL ), | ||
69 | mLabelWidth( label_width ), | ||
70 | mValue( initial_value ), | ||
71 | mEditor( NULL ), | ||
72 | mTextBox( NULL ), | ||
73 | mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), | ||
74 | mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), | ||
75 | mSliderMouseUpCallback( NULL ), | ||
76 | mSliderMouseDownCallback( NULL ) | ||
77 | { | ||
78 | S32 top = mRect.getHeight(); | ||
79 | S32 bottom = 0; | ||
80 | S32 left = 0; | ||
81 | |||
82 | // Label | ||
83 | if( !label.empty() ) | ||
84 | { | ||
85 | if (label_width == 0) | ||
86 | { | ||
87 | label_width = font->getWidth(label); | ||
88 | } | ||
89 | LLRect label_rect( left, top, label_width, bottom ); | ||
90 | mLabelBox = new LLTextBox( "SliderCtrl Label", label_rect, label.c_str(), font ); | ||
91 | addChild(mLabelBox); | ||
92 | } | ||
93 | |||
94 | S32 slider_right = mRect.getWidth(); | ||
95 | if( show_text ) | ||
96 | { | ||
97 | slider_right = text_left - SLIDERCTRL_SPACING; | ||
98 | } | ||
99 | |||
100 | S32 slider_left = label_width ? label_width + SLIDERCTRL_SPACING : 0; | ||
101 | LLRect slider_rect( slider_left, top, slider_right, bottom ); | ||
102 | mSlider = new LLSlider( | ||
103 | "slider", | ||
104 | slider_rect, | ||
105 | LLSliderCtrl::onSliderCommit, this, | ||
106 | initial_value, min_value, max_value, increment, | ||
107 | control_which ); | ||
108 | addChild( mSlider ); | ||
109 | |||
110 | if( show_text ) | ||
111 | { | ||
112 | LLRect text_rect( text_left, top, mRect.getWidth(), bottom ); | ||
113 | if( can_edit_text ) | ||
114 | { | ||
115 | mEditor = new LLLineEditor( "SliderCtrl Editor", text_rect, | ||
116 | "", font, | ||
117 | MAX_STRING_LENGTH, | ||
118 | &LLSliderCtrl::onEditorCommit, NULL, NULL, this, | ||
119 | &LLLineEditor::prevalidateFloat ); | ||
120 | mEditor->setFollowsLeft(); | ||
121 | mEditor->setFollowsBottom(); | ||
122 | mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus ); | ||
123 | mEditor->setIgnoreTab(TRUE); | ||
124 | // don't do this, as selecting the entire text is single clicking in some cases | ||
125 | // and double clicking in others | ||
126 | //mEditor->setSelectAllonFocusReceived(TRUE); | ||
127 | addChild(mEditor); | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | mTextBox = new LLTextBox( "SliderCtrl Text", text_rect, "", font); | ||
132 | mTextBox->setFollowsLeft(); | ||
133 | mTextBox->setFollowsBottom(); | ||
134 | addChild(mTextBox); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | updateText(); | ||
139 | } | ||
140 | |||
141 | LLSliderCtrl::~LLSliderCtrl() | ||
142 | { | ||
143 | // Children all cleaned up by default view destructor. | ||
144 | } | ||
145 | |||
146 | // static | ||
147 | void LLSliderCtrl::onEditorGainFocus( LLUICtrl* caller, void *userdata ) | ||
148 | { | ||
149 | LLSliderCtrl* self = (LLSliderCtrl*) userdata; | ||
150 | llassert( caller == self->mEditor ); | ||
151 | |||
152 | self->onFocusReceived(); | ||
153 | } | ||
154 | |||
155 | F32 LLSliderCtrl::getValueF32() const | ||
156 | { | ||
157 | return mSlider->getValueF32(); | ||
158 | } | ||
159 | |||
160 | void LLSliderCtrl::setValue(F32 v, BOOL from_event) | ||
161 | { | ||
162 | mSlider->setValue( v, from_event ); | ||
163 | mValue = mSlider->getValueF32(); | ||
164 | updateText(); | ||
165 | } | ||
166 | |||
167 | BOOL LLSliderCtrl::setLabelArg( const LLString& key, const LLString& text ) | ||
168 | { | ||
169 | BOOL res = FALSE; | ||
170 | if (mLabelBox) | ||
171 | { | ||
172 | res = mLabelBox->setTextArg(key, text); | ||
173 | if (res && mLabelWidth == 0) | ||
174 | { | ||
175 | S32 label_width = mFont->getWidth(mLabelBox->getText()); | ||
176 | LLRect rect = mLabelBox->getRect(); | ||
177 | S32 prev_right = rect.mRight; | ||
178 | rect.mRight = rect.mLeft + label_width; | ||
179 | mLabelBox->setRect(rect); | ||
180 | |||
181 | S32 delta = rect.mRight - prev_right; | ||
182 | rect = mSlider->getRect(); | ||
183 | S32 left = rect.mLeft + delta; | ||
184 | left = llclamp(left, 0, rect.mRight-SLIDERCTRL_SPACING); | ||
185 | rect.mLeft = left; | ||
186 | mSlider->setRect(rect); | ||
187 | } | ||
188 | } | ||
189 | return res; | ||
190 | } | ||
191 | |||
192 | void LLSliderCtrl::clear() | ||
193 | { | ||
194 | setValue(0.0f); | ||
195 | if( mEditor ) | ||
196 | { | ||
197 | mEditor->setText( "" ); | ||
198 | } | ||
199 | if( mTextBox ) | ||
200 | { | ||
201 | mTextBox->setText( "" ); | ||
202 | } | ||
203 | |||
204 | } | ||
205 | |||
206 | BOOL LLSliderCtrl::isMouseHeldDown() | ||
207 | { | ||
208 | return gFocusMgr.getMouseCapture() == mSlider; | ||
209 | } | ||
210 | |||
211 | void LLSliderCtrl::updateText() | ||
212 | { | ||
213 | if( mEditor || mTextBox ) | ||
214 | { | ||
215 | LLLocale locale(LLLocale::USER_LOCALE); | ||
216 | |||
217 | // Don't display very small negative values as -0.000 | ||
218 | F32 displayed_value = (F32)(floor(getValueF32() * pow(10, mPrecision) + 0.5) / pow(10, mPrecision)); | ||
219 | |||
220 | LLString format = llformat("%%.%df", mPrecision); | ||
221 | LLString text = llformat(format.c_str(), displayed_value); | ||
222 | if( mEditor ) | ||
223 | { | ||
224 | mEditor->setText( text ); | ||
225 | } | ||
226 | else | ||
227 | { | ||
228 | mTextBox->setText( text ); | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | |||
233 | // static | ||
234 | void LLSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata ) | ||
235 | { | ||
236 | LLSliderCtrl* self = (LLSliderCtrl*) userdata; | ||
237 | llassert( caller == self->mEditor ); | ||
238 | |||
239 | BOOL success = FALSE; | ||
240 | F32 val = self->mValue; | ||
241 | F32 saved_val = self->mValue; | ||
242 | |||
243 | LLString text = self->mEditor->getText(); | ||
244 | if( LLLineEditor::postvalidateFloat( text ) ) | ||
245 | { | ||
246 | LLLocale locale(LLLocale::USER_LOCALE); | ||
247 | val = (F32) atof( text.c_str() ); | ||
248 | if( self->mSlider->getMinValue() <= val && val <= self->mSlider->getMaxValue() ) | ||
249 | { | ||
250 | if( self->mValidateCallback ) | ||
251 | { | ||
252 | self->setValue( val ); // set the value temporarily so that the callback can retrieve it. | ||
253 | if( self->mValidateCallback( self, self->mCallbackUserData ) ) | ||
254 | { | ||
255 | success = TRUE; | ||
256 | } | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | self->setValue( val ); | ||
261 | success = TRUE; | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | if( success ) | ||
267 | { | ||
268 | self->onCommit(); | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | if( self->getValueF32() != saved_val ) | ||
273 | { | ||
274 | self->setValue( saved_val ); | ||
275 | } | ||
276 | self->reportInvalidData(); | ||
277 | } | ||
278 | self->updateText(); | ||
279 | } | ||
280 | |||
281 | // static | ||
282 | void LLSliderCtrl::onSliderCommit( LLUICtrl* caller, void *userdata ) | ||
283 | { | ||
284 | LLSliderCtrl* self = (LLSliderCtrl*) userdata; | ||
285 | llassert( caller == self->mSlider ); | ||
286 | |||
287 | BOOL success = FALSE; | ||
288 | F32 saved_val = self->mValue; | ||
289 | F32 new_val = self->mSlider->getValueF32(); | ||
290 | |||
291 | if( self->mValidateCallback ) | ||
292 | { | ||
293 | self->mValue = new_val; // set the value temporarily so that the callback can retrieve it. | ||
294 | if( self->mValidateCallback( self, self->mCallbackUserData ) ) | ||
295 | { | ||
296 | success = TRUE; | ||
297 | } | ||
298 | } | ||
299 | else | ||
300 | { | ||
301 | self->mValue = new_val; | ||
302 | success = TRUE; | ||
303 | } | ||
304 | |||
305 | if( success ) | ||
306 | { | ||
307 | self->onCommit(); | ||
308 | } | ||
309 | else | ||
310 | { | ||
311 | if( self->mValue != saved_val ) | ||
312 | { | ||
313 | self->setValue( saved_val ); | ||
314 | } | ||
315 | self->reportInvalidData(); | ||
316 | } | ||
317 | self->updateText(); | ||
318 | } | ||
319 | |||
320 | void LLSliderCtrl::setEnabled(BOOL b) | ||
321 | { | ||
322 | LLUICtrl::setEnabled( b ); | ||
323 | |||
324 | if( mLabelBox ) | ||
325 | { | ||
326 | mLabelBox->setColor( b ? mTextEnabledColor : mTextDisabledColor ); | ||
327 | } | ||
328 | |||
329 | mSlider->setEnabled( b ); | ||
330 | |||
331 | if( mEditor ) | ||
332 | { | ||
333 | mEditor->setEnabled( b ); | ||
334 | } | ||
335 | |||
336 | if( mTextBox ) | ||
337 | { | ||
338 | mTextBox->setColor( b ? mTextEnabledColor : mTextDisabledColor ); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | |||
343 | void LLSliderCtrl::setTentative(BOOL b) | ||
344 | { | ||
345 | if( mEditor ) | ||
346 | { | ||
347 | mEditor->setTentative(b); | ||
348 | } | ||
349 | LLUICtrl::setTentative(b); | ||
350 | } | ||
351 | |||
352 | |||
353 | void LLSliderCtrl::onCommit() | ||
354 | { | ||
355 | setTentative(FALSE); | ||
356 | |||
357 | if( mEditor ) | ||
358 | { | ||
359 | mEditor->setTentative(FALSE); | ||
360 | } | ||
361 | |||
362 | LLUICtrl::onCommit(); | ||
363 | } | ||
364 | |||
365 | |||
366 | void LLSliderCtrl::setPrecision(S32 precision) | ||
367 | { | ||
368 | if (precision < 0 || precision > 10) | ||
369 | { | ||
370 | llerrs << "LLSliderCtrl::setPrecision - precision out of range" << llendl; | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | mPrecision = precision; | ||
375 | updateText(); | ||
376 | } | ||
377 | |||
378 | void LLSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) ) | ||
379 | { | ||
380 | mSliderMouseDownCallback = slider_mousedown_callback; | ||
381 | mSlider->setMouseDownCallback( LLSliderCtrl::onSliderMouseDown ); | ||
382 | } | ||
383 | |||
384 | // static | ||
385 | void LLSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata) | ||
386 | { | ||
387 | LLSliderCtrl* self = (LLSliderCtrl*) userdata; | ||
388 | if( self->mSliderMouseDownCallback ) | ||
389 | { | ||
390 | self->mSliderMouseDownCallback( self, self->mCallbackUserData ); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | |||
395 | void LLSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) ) | ||
396 | { | ||
397 | mSliderMouseUpCallback = slider_mouseup_callback; | ||
398 | mSlider->setMouseUpCallback( LLSliderCtrl::onSliderMouseUp ); | ||
399 | } | ||
400 | |||
401 | // static | ||
402 | void LLSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata) | ||
403 | { | ||
404 | LLSliderCtrl* self = (LLSliderCtrl*) userdata; | ||
405 | if( self->mSliderMouseUpCallback ) | ||
406 | { | ||
407 | self->mSliderMouseUpCallback( self, self->mCallbackUserData ); | ||
408 | } | ||
409 | } | ||
410 | |||
411 | void LLSliderCtrl::onTabInto() | ||
412 | { | ||
413 | if( mEditor ) | ||
414 | { | ||
415 | mEditor->onTabInto(); | ||
416 | } | ||
417 | } | ||
418 | |||
419 | void LLSliderCtrl::reportInvalidData() | ||
420 | { | ||
421 | make_ui_sound("UISndBadKeystroke"); | ||
422 | } | ||
423 | |||
424 | //virtual | ||
425 | LLString LLSliderCtrl::getControlName() const | ||
426 | { | ||
427 | return mSlider->getControlName(); | ||
428 | } | ||
429 | |||
430 | // virtual | ||
431 | void LLSliderCtrl::setControlName(const LLString& control_name, LLView* context) | ||
432 | { | ||
433 | mSlider->setControlName(control_name, context); | ||
434 | } | ||
435 | |||
436 | // virtual | ||
437 | LLXMLNodePtr LLSliderCtrl::getXML(bool save_children) const | ||
438 | { | ||
439 | LLXMLNodePtr node = LLUICtrl::getXML(); | ||
440 | |||
441 | node->createChild("show_text", TRUE)->setBoolValue(mShowText); | ||
442 | |||
443 | node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText); | ||
444 | |||
445 | node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision); | ||
446 | |||
447 | if (mLabelBox) | ||
448 | { | ||
449 | node->createChild("label", TRUE)->setStringValue(mLabelBox->getText()); | ||
450 | } | ||
451 | |||
452 | // TomY TODO: Do we really want to export the transient state of the slider? | ||
453 | node->createChild("value", TRUE)->setFloatValue(mValue); | ||
454 | |||
455 | if (mSlider) | ||
456 | { | ||
457 | node->createChild("initial_val", TRUE)->setFloatValue(mSlider->getInitialValue()); | ||
458 | node->createChild("min_val", TRUE)->setFloatValue(mSlider->getMinValue()); | ||
459 | node->createChild("max_val", TRUE)->setFloatValue(mSlider->getMaxValue()); | ||
460 | node->createChild("increment", TRUE)->setFloatValue(mSlider->getIncrement()); | ||
461 | } | ||
462 | addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor"); | ||
463 | addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor"); | ||
464 | |||
465 | return node; | ||
466 | } | ||
467 | |||
468 | LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) | ||
469 | { | ||
470 | LLString name("slider"); | ||
471 | node->getAttributeString("name", name); | ||
472 | |||
473 | LLString label; | ||
474 | node->getAttributeString("label", label); | ||
475 | |||
476 | LLRect rect; | ||
477 | createRect(node, rect, parent, LLRect()); | ||
478 | |||
479 | LLFontGL* font = LLView::selectFont(node); | ||
480 | |||
481 | // HACK: Font might not be specified. | ||
482 | if (!font) | ||
483 | { | ||
484 | font = LLFontGL::sSansSerifSmall; | ||
485 | } | ||
486 | |||
487 | S32 label_width = 0; | ||
488 | node->getAttributeS32("label_width", label_width); | ||
489 | |||
490 | BOOL show_text = TRUE; | ||
491 | node->getAttributeBOOL("show_text", show_text); | ||
492 | |||
493 | BOOL can_edit_text = FALSE; | ||
494 | node->getAttributeBOOL("can_edit_text", can_edit_text); | ||
495 | |||
496 | F32 initial_value = 0.f; | ||
497 | node->getAttributeF32("initial_val", initial_value); | ||
498 | |||
499 | F32 min_value = 0.f; | ||
500 | node->getAttributeF32("min_val", min_value); | ||
501 | |||
502 | F32 max_value = 1.f; | ||
503 | node->getAttributeF32("max_val", max_value); | ||
504 | |||
505 | F32 increment = 0.1f; | ||
506 | node->getAttributeF32("increment", increment); | ||
507 | |||
508 | U32 precision = 3; | ||
509 | node->getAttributeU32("decimal_digits", precision); | ||
510 | |||
511 | S32 text_left = 0; | ||
512 | if (show_text) | ||
513 | { | ||
514 | // calculate the size of the text box (log max_value is number of digits - 1 so plus 1) | ||
515 | if ( max_value ) | ||
516 | text_left = font->getWidth("0") * ( static_cast < S32 > ( log10 ( max_value ) ) + precision + 1 ); | ||
517 | |||
518 | if ( increment < 1.0f ) | ||
519 | text_left += font->getWidth("."); // (mostly) take account of decimal point in value | ||
520 | |||
521 | if ( min_value < 0.0f || max_value < 0.0f ) | ||
522 | text_left += font->getWidth("-"); // (mostly) take account of minus sign | ||
523 | |||
524 | // padding to make things look nicer | ||
525 | text_left += 8; | ||
526 | } | ||
527 | |||
528 | LLUICtrlCallback callback = NULL; | ||
529 | |||
530 | if (label.empty()) | ||
531 | { | ||
532 | label.assign(node->getTextContents()); | ||
533 | } | ||
534 | |||
535 | LLSliderCtrl* slider = new LLSliderCtrl(name, | ||
536 | rect, | ||
537 | label, | ||
538 | font, | ||
539 | label_width, | ||
540 | rect.getWidth() - text_left, | ||
541 | show_text, | ||
542 | can_edit_text, | ||
543 | callback, | ||
544 | NULL, | ||
545 | initial_value, | ||
546 | min_value, | ||
547 | max_value, | ||
548 | increment); | ||
549 | |||
550 | slider->setPrecision(precision); | ||
551 | |||
552 | slider->initFromXML(node, parent); | ||
553 | |||
554 | slider->updateText(); | ||
555 | |||
556 | return slider; | ||
557 | } | ||