aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/llspinctrl.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/llspinctrl.cpp
parentREADME.txt (diff)
downloadmeta-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/llspinctrl.cpp')
-rw-r--r--linden/indra/llui/llspinctrl.cpp528
1 files changed, 528 insertions, 0 deletions
diff --git a/linden/indra/llui/llspinctrl.cpp b/linden/indra/llui/llspinctrl.cpp
new file mode 100644
index 0000000..b93ed02
--- /dev/null
+++ b/linden/indra/llui/llspinctrl.cpp
@@ -0,0 +1,528 @@
1/**
2 * @file llspinctrl.cpp
3 * @brief LLSpinCtrl base class
4 *
5 * Copyright (c) 2001-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 "llspinctrl.h"
31
32#include "llgl.h"
33#include "llui.h"
34#include "lluiconstants.h"
35
36#include "llstring.h"
37#include "llfontgl.h"
38#include "lllineeditor.h"
39#include "llbutton.h"
40#include "lltextbox.h"
41#include "llkeyboard.h"
42#include "llmath.h"
43#include "sound_ids.h"
44#include "audioengine.h"
45#include "llcontrol.h"
46#include "llfocusmgr.h"
47#include "llresmgr.h"
48
49const U32 MAX_STRING_LENGTH = 32;
50
51
52LLSpinCtrl::LLSpinCtrl( const LLString& name, const LLRect& rect, const LLString& label, const LLFontGL* font,
53 void (*commit_callback)(LLUICtrl*, void*),
54 void* callback_user_data,
55 F32 initial_value, F32 min_value, F32 max_value, F32 increment,
56 const LLString& control_name,
57 S32 label_width)
58 :
59 LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data, FOLLOWS_LEFT | FOLLOWS_TOP ),
60 mValue( initial_value ),
61 mInitialValue( initial_value ),
62 mMaxValue( max_value ),
63 mMinValue( min_value ),
64 mIncrement( increment ),
65 mPrecision( 3 ),
66 mLabelBox( NULL ),
67 mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
68 mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
69 mbHasBeenSet( FALSE )
70{
71 S32 top = mRect.getHeight();
72 S32 bottom = top - 2 * SPINCTRL_BTN_HEIGHT;
73 S32 centered_top = top;
74 S32 centered_bottom = bottom;
75 S32 btn_left = 0;
76
77 // Label
78 if( !label.empty() )
79 {
80 LLRect label_rect( 0, centered_top, label_width, centered_bottom );
81 mLabelBox = new LLTextBox( "SpinCtrl Label", label_rect, label.c_str(), font );
82 addChild(mLabelBox);
83
84 btn_left += label_rect.mRight + SPINCTRL_SPACING;
85 }
86
87 S32 btn_right = btn_left + SPINCTRL_BTN_WIDTH;
88
89 // Spin buttons
90 LLRect up_rect( btn_left, top, btn_right, top - SPINCTRL_BTN_HEIGHT );
91 LLString out_id = "UIImgBtnSpinUpOutUUID";
92 LLString in_id = "UIImgBtnSpinUpInUUID";
93 mUpBtn = new LLButton(
94 "SpinCtrl Up", up_rect,
95 out_id,
96 in_id,
97 "",
98 &LLSpinCtrl::onUpBtn, this, LLFontGL::sSansSerif );
99 mUpBtn->setFollowsLeft();
100 mUpBtn->setFollowsBottom();
101 mUpBtn->setHeldDownCallback( &LLSpinCtrl::onUpBtn );
102 mUpBtn->setTabStop(FALSE);
103 addChild(mUpBtn);
104
105 LLRect down_rect( btn_left, top - SPINCTRL_BTN_HEIGHT, btn_right, bottom );
106 out_id = "UIImgBtnSpinDownOutUUID";
107 in_id = "UIImgBtnSpinDownInUUID";
108 mDownBtn = new LLButton(
109 "SpinCtrl Down", down_rect,
110 out_id,
111 in_id,
112 "",
113 &LLSpinCtrl::onDownBtn, this, LLFontGL::sSansSerif );
114 mDownBtn->setFollowsLeft();
115 mDownBtn->setFollowsBottom();
116 mDownBtn->setHeldDownCallback( &LLSpinCtrl::onDownBtn );
117 mDownBtn->setTabStop(FALSE);
118 addChild(mDownBtn);
119
120 LLRect editor_rect( btn_right + 1, centered_top, mRect.getWidth(), centered_bottom );
121 mEditor = new LLLineEditor( "SpinCtrl Editor", editor_rect, "", font,
122 MAX_STRING_LENGTH,
123 &LLSpinCtrl::onEditorCommit, NULL, NULL, this,
124 &LLLineEditor::prevalidateFloat );
125 mEditor->setFollowsLeft();
126 mEditor->setFollowsBottom();
127 mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus );
128 //RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus
129 // than when it doesn't. Instead, if you always have to double click to select all the text,
130 // it's easier to understand
131 //mEditor->setSelectAllonFocusReceived(TRUE);
132 mEditor->setIgnoreTab(TRUE);
133 addChild(mEditor);
134
135 updateEditor();
136 setSpanChildren( TRUE );
137}
138
139LLSpinCtrl::~LLSpinCtrl()
140{
141 // Children all cleaned up by default view destructor.
142}
143
144
145// static
146void LLSpinCtrl::onUpBtn( void *userdata )
147{
148 LLSpinCtrl* self = (LLSpinCtrl*) userdata;
149 if( self->getEnabled() )
150 {
151 // use getValue()/setValue() to force reload from/to control
152 F32 val = (F32)self->getValue().asReal() + self->mIncrement;
153 val = llmin( val, self->mMaxValue );
154
155 if( self->mValidateCallback )
156 {
157 F32 saved_val = (F32)self->getValue().asReal();
158 self->setValue(val);
159 if( !self->mValidateCallback( self, self->mCallbackUserData ) )
160 {
161 self->setValue( saved_val );
162 self->reportInvalidData();
163 self->updateEditor();
164 return;
165 }
166 }
167 else
168 {
169 self->setValue(val);
170 }
171
172 self->updateEditor();
173 self->onCommit();
174 }
175}
176
177// static
178void LLSpinCtrl::onDownBtn( void *userdata )
179{
180 LLSpinCtrl* self = (LLSpinCtrl*) userdata;
181
182 if( self->getEnabled() )
183 {
184 F32 val = (F32)self->getValue().asReal() - self->mIncrement;
185 val = llmax( val, self->mMinValue );
186
187 if( self->mValidateCallback )
188 {
189 F32 saved_val = (F32)self->getValue().asReal();
190 self->setValue(val);
191 if( !self->mValidateCallback( self, self->mCallbackUserData ) )
192 {
193 self->setValue( saved_val );
194 self->reportInvalidData();
195 self->updateEditor();
196 return;
197 }
198 }
199 else
200 {
201 self->setValue(val);
202 }
203
204 self->updateEditor();
205 self->onCommit();
206 }
207}
208
209// static
210void LLSpinCtrl::onEditorGainFocus( LLUICtrl* caller, void *userdata )
211{
212 LLSpinCtrl* self = (LLSpinCtrl*) userdata;
213 llassert( caller == self->mEditor );
214
215 self->onFocusReceived();
216}
217
218void LLSpinCtrl::setValue(const LLSD& value )
219{
220 F32 v = (F32)value.asReal();
221 if (mValue != v || !mbHasBeenSet)
222 {
223 mbHasBeenSet = TRUE;
224 mValue = v;
225
226 if (!mEditor->hasFocus())
227 {
228 updateEditor();
229 }
230 }
231}
232
233LLSD LLSpinCtrl::getValue() const
234{
235 return mValue;
236}
237
238void LLSpinCtrl::clear()
239{
240 setValue(mMinValue);
241 mEditor->clear();
242 mbHasBeenSet = FALSE;
243}
244
245
246void LLSpinCtrl::updateEditor()
247{
248 LLLocale locale(LLLocale::USER_LOCALE);
249
250 // Don't display very small negative values as -0.000
251 F32 displayed_value = (F32)floor(getValue().asReal() * pow(10, mPrecision) + 0.5) / (F32)pow(10, mPrecision);
252
253// if( S32( displayed_value * pow( 10, mPrecision ) ) == 0 )
254// {
255// displayed_value = 0.f;
256// }
257
258 LLString format = llformat("%%.%df", mPrecision);
259 LLString text = llformat(format.c_str(), displayed_value);
260 mEditor->setText( text );
261}
262
263void LLSpinCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
264{
265 BOOL success = FALSE;
266
267 LLSpinCtrl* self = (LLSpinCtrl*) userdata;
268 llassert( caller == self->mEditor );
269
270 LLString text = self->mEditor->getText();
271 if( LLLineEditor::postvalidateFloat( text ) )
272 {
273 LLLocale locale(LLLocale::USER_LOCALE);
274 F32 val = (F32) atof(text.c_str());
275
276 if (val < self->mMinValue) val = self->mMinValue;
277 if (val > self->mMaxValue) val = self->mMaxValue;
278
279 if( self->mValidateCallback )
280 {
281 F32 saved_val = self->mValue;
282 self->mValue = val;
283 if( self->mValidateCallback( self, self->mCallbackUserData ) )
284 {
285 success = TRUE;
286 self->onCommit();
287 }
288 else
289 {
290 self->mValue = saved_val;
291 }
292 }
293 else
294 {
295 self->mValue = val;
296 self->onCommit();
297 success = TRUE;
298 }
299 }
300 self->updateEditor();
301
302 if( !success )
303 {
304 self->reportInvalidData();
305 }
306}
307
308
309void LLSpinCtrl::forceEditorCommit()
310{
311 onEditorCommit(mEditor, this);
312}
313
314
315void LLSpinCtrl::setFocus(BOOL b)
316{
317 LLUICtrl::setFocus( b );
318 mEditor->setFocus( b );
319}
320
321void LLSpinCtrl::setEnabled(BOOL b)
322{
323 LLUICtrl::setEnabled( b );
324 mEditor->setEnabled( b );
325}
326
327
328void LLSpinCtrl::setTentative(BOOL b)
329{
330 mEditor->setTentative(b);
331 LLUICtrl::setTentative(b);
332}
333
334
335BOOL LLSpinCtrl::isMouseHeldDown()
336{
337 return
338 gFocusMgr.getMouseCapture() == mDownBtn ||
339 gFocusMgr.getMouseCapture() == mUpBtn;
340}
341
342void LLSpinCtrl::onCommit()
343{
344 setTentative(FALSE);
345
346 setControlValue(mValue);
347
348 LLUICtrl::onCommit();
349}
350
351
352void LLSpinCtrl::setPrecision(S32 precision)
353{
354 if (precision < 0 || precision > 10)
355 {
356 llerrs << "LLSpinCtrl::setPrecision - precision out of range" << llendl;
357 return;
358 }
359
360 mPrecision = precision;
361 updateEditor();
362}
363
364void LLSpinCtrl::setLabel(const LLString& label)
365{
366 if (mLabelBox)
367 {
368 mLabelBox->setText(label);
369 }
370 else
371 {
372 llwarns << "Attempting to set label on LLSpinCtrl constructed without one " << getName() << llendl;
373 }
374}
375
376void LLSpinCtrl::onTabInto()
377{
378 mEditor->onTabInto();
379}
380
381
382void LLSpinCtrl::reportInvalidData()
383{
384 make_ui_sound("UISndBadKeystroke");
385}
386
387void LLSpinCtrl::draw()
388{
389 if( mLabelBox )
390 {
391 mLabelBox->setColor( mEnabled ? mTextEnabledColor : mTextDisabledColor );
392 }
393 LLUICtrl::draw();
394}
395
396
397BOOL LLSpinCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
398{
399 if( mEnabled )
400 {
401 if( clicks > 0 )
402 {
403 while( clicks-- )
404 {
405 LLSpinCtrl::onDownBtn(this);
406 }
407 }
408 else
409 while( clicks++ )
410 {
411 LLSpinCtrl::onUpBtn(this);
412 }
413 }
414
415 return TRUE;
416}
417
418BOOL LLSpinCtrl::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
419{
420 if (mEditor->hasFocus())
421 {
422 if(key == KEY_ESCAPE)
423 {
424 // text editors don't support revert normally (due to user confusion)
425 // but not allowing revert on a spinner seems dangerous
426 updateEditor();
427 mEditor->setFocus(FALSE);
428 return TRUE;
429 }
430 if(key == KEY_UP)
431 {
432 LLSpinCtrl::onUpBtn(this);
433 return TRUE;
434 }
435 if(key == KEY_DOWN)
436 {
437 LLSpinCtrl::onDownBtn(this);
438 return TRUE;
439 }
440 }
441 return FALSE;
442}
443
444// virtual
445LLXMLNodePtr LLSpinCtrl::getXML(bool save_children) const
446{
447 LLXMLNodePtr node = LLUICtrl::getXML();
448
449 node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision);
450
451 if (mLabelBox)
452 {
453 node->createChild("label", TRUE)->setStringValue(mLabelBox->getText());
454
455 node->createChild("label_width", TRUE)->setIntValue(mLabelBox->getRect().getWidth());
456 }
457
458 node->createChild("initial_val", TRUE)->setFloatValue(mInitialValue);
459
460 node->createChild("min_val", TRUE)->setFloatValue(mMinValue);
461
462 node->createChild("max_val", TRUE)->setFloatValue(mMaxValue);
463
464 node->createChild("increment", TRUE)->setFloatValue(mIncrement);
465
466 addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor");
467 addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor");
468
469 return node;
470}
471
472LLView* LLSpinCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
473{
474 LLString name("spinner");
475 node->getAttributeString("name", name);
476
477 LLString label;
478 node->getAttributeString("label", label);
479
480 LLRect rect;
481 createRect(node, rect, parent, LLRect());
482
483 LLFontGL* font = LLView::selectFont(node);
484
485 F32 initial_value = 0.f;
486 node->getAttributeF32("initial_val", initial_value);
487
488 F32 min_value = 0.f;
489 node->getAttributeF32("min_val", min_value);
490
491 F32 max_value = 1.f;
492 node->getAttributeF32("max_val", max_value);
493
494 F32 increment = 0.1f;
495 node->getAttributeF32("increment", increment);
496
497 U32 precision = 3;
498 node->getAttributeU32("decimal_digits", precision);
499
500 S32 label_width = llmin(40, rect.getWidth() - 40);
501 node->getAttributeS32("label_width", label_width);
502
503 LLUICtrlCallback callback = NULL;
504
505 if(label.empty())
506 {
507 label.assign( node->getValue() );
508 }
509
510 LLSpinCtrl* spinner = new LLSpinCtrl(name,
511 rect,
512 label,
513 font,
514 callback,
515 NULL,
516 initial_value,
517 min_value,
518 max_value,
519 increment,
520 "",
521 label_width);
522
523 spinner->setPrecision(precision);
524
525 spinner->initFromXML(node, parent);
526
527 return spinner;
528}