diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llui/llmultislider.cpp | 677 |
1 files changed, 677 insertions, 0 deletions
diff --git a/linden/indra/llui/llmultislider.cpp b/linden/indra/llui/llmultislider.cpp new file mode 100644 index 0000000..d0c9002 --- /dev/null +++ b/linden/indra/llui/llmultislider.cpp | |||
@@ -0,0 +1,677 @@ | |||
1 | /** | ||
2 | * @file llmultisldr.cpp | ||
3 | * @brief LLMultiSlider base class | ||
4 | * | ||
5 | * $LicenseInfo:firstyear=2007&license=viewergpl$ | ||
6 | * | ||
7 | * Copyright (c) 2007-2008, Linden Research, Inc. | ||
8 | * | ||
9 | * Second Life Viewer Source Code | ||
10 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
11 | * to you under the terms of the GNU General Public License, version 2.0 | ||
12 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
13 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
15 | * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 | ||
16 | * | ||
17 | * There are special exceptions to the terms and conditions of the GPL as | ||
18 | * it is applied to this Source Code. View the full text of the exception | ||
19 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
20 | * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception | ||
21 | * | ||
22 | * By copying, modifying or distributing this software, you acknowledge | ||
23 | * that you have read and understood your obligations described above, | ||
24 | * and agree to abide by those obligations. | ||
25 | * | ||
26 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
27 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
28 | * COMPLETENESS OR PERFORMANCE. | ||
29 | * $/LicenseInfo$ | ||
30 | */ | ||
31 | |||
32 | #include "linden_common.h" | ||
33 | |||
34 | #include "llmultislider.h" | ||
35 | #include "llui.h" | ||
36 | |||
37 | #include "llgl.h" | ||
38 | #include "llwindow.h" | ||
39 | #include "llfocusmgr.h" | ||
40 | #include "llkeyboard.h" // for the MASK constants | ||
41 | #include "llcontrol.h" | ||
42 | #include "llimagegl.h" | ||
43 | |||
44 | #include <sstream> | ||
45 | |||
46 | const S32 MULTI_THUMB_WIDTH = 8; | ||
47 | const S32 MULTI_TRACK_HEIGHT = 6; | ||
48 | const F32 FLOAT_THRESHOLD = 0.00001f; | ||
49 | const S32 EXTRA_TRIANGLE_WIDTH = 2; | ||
50 | const S32 EXTRA_TRIANGLE_HEIGHT = -2; | ||
51 | |||
52 | S32 LLMultiSlider::mNameCounter = 0; | ||
53 | |||
54 | LLMultiSlider::LLMultiSlider( | ||
55 | const LLString& name, | ||
56 | const LLRect& rect, | ||
57 | void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata), | ||
58 | void* callback_userdata, | ||
59 | F32 initial_value, | ||
60 | F32 min_value, | ||
61 | F32 max_value, | ||
62 | F32 increment, | ||
63 | S32 max_sliders, | ||
64 | BOOL allow_overlap, | ||
65 | BOOL draw_track, | ||
66 | BOOL use_triangle, | ||
67 | const LLString& control_name) | ||
68 | : | ||
69 | LLUICtrl( name, rect, TRUE, on_commit_callback, callback_userdata, | ||
70 | FOLLOWS_LEFT | FOLLOWS_TOP), | ||
71 | |||
72 | mInitialValue( initial_value ), | ||
73 | mMinValue( min_value ), | ||
74 | mMaxValue( max_value ), | ||
75 | mIncrement( increment ), | ||
76 | mMaxNumSliders(max_sliders), | ||
77 | mAllowOverlap(allow_overlap), | ||
78 | mDrawTrack(draw_track), | ||
79 | mUseTriangle(use_triangle), | ||
80 | mMouseOffset( 0 ), | ||
81 | mDragStartThumbRect( 0, getRect().getHeight(), MULTI_THUMB_WIDTH, 0 ), | ||
82 | mTrackColor( LLUI::sColorsGroup->getColor( "MultiSliderTrackColor" ) ), | ||
83 | mThumbOutlineColor( LLUI::sColorsGroup->getColor( "MultiSliderThumbOutlineColor" ) ), | ||
84 | mThumbCenterColor( LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterColor" ) ), | ||
85 | mThumbCenterSelectedColor( LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterSelectedColor" ) ), | ||
86 | mDisabledThumbColor(LLUI::sColorsGroup->getColor( "MultiSliderDisabledThumbColor" ) ), | ||
87 | mTriangleColor(LLUI::sColorsGroup->getColor( "MultiSliderTriangleColor" ) ), | ||
88 | mMouseDownCallback( NULL ), | ||
89 | mMouseUpCallback( NULL ) | ||
90 | { | ||
91 | mValue.emptyMap(); | ||
92 | mCurSlider = LLString::null; | ||
93 | |||
94 | // properly handle setting the starting thumb rect | ||
95 | // do it this way to handle both the operating-on-settings | ||
96 | // and standalone ways of using this | ||
97 | setControlName(control_name, NULL); | ||
98 | setValue(getValue()); | ||
99 | } | ||
100 | |||
101 | EWidgetType LLMultiSlider::getWidgetType() const | ||
102 | { | ||
103 | return WIDGET_TYPE_MULTI_SLIDER_BAR; | ||
104 | } | ||
105 | |||
106 | LLString LLMultiSlider::getWidgetTag() const | ||
107 | { | ||
108 | return LL_MULTI_SLIDER_TAG; | ||
109 | } | ||
110 | |||
111 | void LLMultiSlider::setSliderValue(const LLString& name, F32 value, BOOL from_event) | ||
112 | { | ||
113 | // exit if not there | ||
114 | if(!mValue.has(name)) { | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | value = llclamp( value, mMinValue, mMaxValue ); | ||
119 | |||
120 | // Round to nearest increment (bias towards rounding down) | ||
121 | value -= mMinValue; | ||
122 | value += mIncrement/2.0001f; | ||
123 | value -= fmod(value, mIncrement); | ||
124 | F32 newValue = mMinValue + value; | ||
125 | |||
126 | // now, make sure no overlap | ||
127 | // if we want that | ||
128 | if(!mAllowOverlap) { | ||
129 | bool hit = false; | ||
130 | |||
131 | // look at the current spot | ||
132 | // and see if anything is there | ||
133 | LLSD::map_iterator mIt = mValue.beginMap(); | ||
134 | for(;mIt != mValue.endMap(); mIt++) { | ||
135 | |||
136 | F32 testVal = (F32)mIt->second.asReal() - newValue; | ||
137 | if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD && | ||
138 | mIt->first != name) { | ||
139 | hit = true; | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | // if none found, stop | ||
145 | if(hit) { | ||
146 | return; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | |||
151 | // now set it in the map | ||
152 | mValue[name] = newValue; | ||
153 | |||
154 | // set the control if it's the current slider and not from an event | ||
155 | if (!from_event && name == mCurSlider) | ||
156 | { | ||
157 | setControlValue(mValue); | ||
158 | } | ||
159 | |||
160 | F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue); | ||
161 | |||
162 | S32 left_edge = MULTI_THUMB_WIDTH/2; | ||
163 | S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2); | ||
164 | |||
165 | S32 x = left_edge + S32( t * (right_edge - left_edge) ); | ||
166 | mThumbRects[name].mLeft = x - (MULTI_THUMB_WIDTH/2); | ||
167 | mThumbRects[name].mRight = x + (MULTI_THUMB_WIDTH/2); | ||
168 | } | ||
169 | |||
170 | void LLMultiSlider::setValue(const LLSD& value) | ||
171 | { | ||
172 | // only do if it's a map | ||
173 | if(value.isMap()) { | ||
174 | |||
175 | // add each value... the first in the map becomes the current | ||
176 | LLSD::map_const_iterator mIt = value.beginMap(); | ||
177 | mCurSlider = mIt->first; | ||
178 | |||
179 | for(; mIt != value.endMap(); mIt++) { | ||
180 | setSliderValue(mIt->first, (F32)mIt->second.asReal(), TRUE); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | F32 LLMultiSlider::getSliderValue(const LLString& name) const | ||
186 | { | ||
187 | return (F32)mValue[name].asReal(); | ||
188 | } | ||
189 | |||
190 | void LLMultiSlider::setCurSlider(const LLString& name) | ||
191 | { | ||
192 | if(mValue.has(name)) { | ||
193 | mCurSlider = name; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | const LLString& LLMultiSlider::addSlider() | ||
198 | { | ||
199 | return addSlider(mInitialValue); | ||
200 | } | ||
201 | |||
202 | const LLString& LLMultiSlider::addSlider(F32 val) | ||
203 | { | ||
204 | std::stringstream newName; | ||
205 | F32 initVal = val; | ||
206 | |||
207 | if(mValue.size() >= mMaxNumSliders) { | ||
208 | return LLString::null; | ||
209 | } | ||
210 | |||
211 | // create a new name | ||
212 | newName << "sldr" << mNameCounter; | ||
213 | mNameCounter++; | ||
214 | |||
215 | bool foundOne = findUnusedValue(initVal); | ||
216 | if(!foundOne) { | ||
217 | return LLString::null; | ||
218 | } | ||
219 | |||
220 | // add a new thumb rect | ||
221 | mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), MULTI_THUMB_WIDTH, 0 ); | ||
222 | |||
223 | // add the value and set the current slider to this one | ||
224 | mValue.insert(newName.str(), initVal); | ||
225 | mCurSlider = newName.str(); | ||
226 | |||
227 | // move the slider | ||
228 | setSliderValue(mCurSlider, initVal, TRUE); | ||
229 | |||
230 | return mCurSlider; | ||
231 | } | ||
232 | |||
233 | bool LLMultiSlider::findUnusedValue(F32& initVal) | ||
234 | { | ||
235 | bool firstTry = true; | ||
236 | |||
237 | // find the first open slot starting with | ||
238 | // the initial value | ||
239 | while(true) { | ||
240 | |||
241 | bool hit = false; | ||
242 | |||
243 | // look at the current spot | ||
244 | // and see if anything is there | ||
245 | LLSD::map_iterator mIt = mValue.beginMap(); | ||
246 | for(;mIt != mValue.endMap(); mIt++) { | ||
247 | |||
248 | F32 testVal = (F32)mIt->second.asReal() - initVal; | ||
249 | if(testVal > -FLOAT_THRESHOLD && testVal < FLOAT_THRESHOLD) { | ||
250 | hit = true; | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | // if we found one | ||
256 | if(!hit) { | ||
257 | break; | ||
258 | } | ||
259 | |||
260 | // increment and wrap if need be | ||
261 | initVal += mIncrement; | ||
262 | if(initVal > mMaxValue) { | ||
263 | initVal = mMinValue; | ||
264 | } | ||
265 | |||
266 | // stop if it's filled | ||
267 | if(initVal == mInitialValue && !firstTry) { | ||
268 | llwarns << "Whoa! Too many multi slider elements to add one to" << llendl; | ||
269 | return false; | ||
270 | } | ||
271 | |||
272 | firstTry = false; | ||
273 | continue; | ||
274 | } | ||
275 | |||
276 | return true; | ||
277 | } | ||
278 | |||
279 | |||
280 | void LLMultiSlider::deleteSlider(const LLString& name) | ||
281 | { | ||
282 | // can't delete last slider | ||
283 | if(mValue.size() <= 0) { | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | // get rid of value from mValue and its thumb rect | ||
288 | mValue.erase(name); | ||
289 | mThumbRects.erase(name); | ||
290 | |||
291 | // set to the last created | ||
292 | if(mValue.size() > 0) { | ||
293 | std::map<LLString, LLRect>::iterator mIt = mThumbRects.end(); | ||
294 | mIt--; | ||
295 | mCurSlider = mIt->first; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | void LLMultiSlider::clear() | ||
300 | { | ||
301 | while(mThumbRects.size() > 0) { | ||
302 | deleteCurSlider(); | ||
303 | } | ||
304 | |||
305 | LLUICtrl::clear(); | ||
306 | } | ||
307 | |||
308 | BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask) | ||
309 | { | ||
310 | if( gFocusMgr.getMouseCapture() == this ) | ||
311 | { | ||
312 | S32 left_edge = MULTI_THUMB_WIDTH/2; | ||
313 | S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2); | ||
314 | |||
315 | x += mMouseOffset; | ||
316 | x = llclamp( x, left_edge, right_edge ); | ||
317 | |||
318 | F32 t = F32(x - left_edge) / (right_edge - left_edge); | ||
319 | setCurSliderValue(t * (mMaxValue - mMinValue) + mMinValue ); | ||
320 | onCommit(); | ||
321 | |||
322 | getWindow()->setCursor(UI_CURSOR_ARROW); | ||
323 | lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | getWindow()->setCursor(UI_CURSOR_ARROW); | ||
328 | lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; | ||
329 | } | ||
330 | return TRUE; | ||
331 | } | ||
332 | |||
333 | BOOL LLMultiSlider::handleMouseUp(S32 x, S32 y, MASK mask) | ||
334 | { | ||
335 | BOOL handled = FALSE; | ||
336 | |||
337 | if( gFocusMgr.getMouseCapture() == this ) | ||
338 | { | ||
339 | gFocusMgr.setMouseCapture( NULL ); | ||
340 | |||
341 | if( mMouseUpCallback ) | ||
342 | { | ||
343 | mMouseUpCallback( this, mCallbackUserData ); | ||
344 | } | ||
345 | handled = TRUE; | ||
346 | make_ui_sound("UISndClickRelease"); | ||
347 | } | ||
348 | else | ||
349 | { | ||
350 | handled = TRUE; | ||
351 | } | ||
352 | |||
353 | return handled; | ||
354 | } | ||
355 | |||
356 | BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask) | ||
357 | { | ||
358 | // only do sticky-focus on non-chrome widgets | ||
359 | if (!getIsChrome()) | ||
360 | { | ||
361 | setFocus(TRUE); | ||
362 | } | ||
363 | if( mMouseDownCallback ) | ||
364 | { | ||
365 | mMouseDownCallback( this, mCallbackUserData ); | ||
366 | } | ||
367 | |||
368 | if (MASK_CONTROL & mask) // if CTRL is modifying | ||
369 | { | ||
370 | setCurSliderValue(mInitialValue); | ||
371 | onCommit(); | ||
372 | } | ||
373 | else | ||
374 | { | ||
375 | // scroll through thumbs to see if we have a new one selected and select that one | ||
376 | std::map<LLString, LLRect>::iterator mIt = mThumbRects.begin(); | ||
377 | for(; mIt != mThumbRects.end(); mIt++) { | ||
378 | |||
379 | // check if inside. If so, set current slider and continue | ||
380 | if(mIt->second.pointInRect(x,y)) { | ||
381 | mCurSlider = mIt->first; | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | // Find the offset of the actual mouse location from the center of the thumb. | ||
387 | if (mThumbRects[mCurSlider].pointInRect(x,y)) | ||
388 | { | ||
389 | mMouseOffset = (mThumbRects[mCurSlider].mLeft + MULTI_THUMB_WIDTH/2) - x; | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | mMouseOffset = 0; | ||
394 | } | ||
395 | |||
396 | // Start dragging the thumb | ||
397 | // No handler needed for focus lost since this class has no state that depends on it. | ||
398 | gFocusMgr.setMouseCapture( this ); | ||
399 | mDragStartThumbRect = mThumbRects[mCurSlider]; | ||
400 | } | ||
401 | make_ui_sound("UISndClick"); | ||
402 | |||
403 | return TRUE; | ||
404 | } | ||
405 | |||
406 | BOOL LLMultiSlider::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) | ||
407 | { | ||
408 | BOOL handled = FALSE; | ||
409 | if( getVisible() && getEnabled() && !called_from_parent ) | ||
410 | { | ||
411 | switch(key) | ||
412 | { | ||
413 | case KEY_UP: | ||
414 | case KEY_DOWN: | ||
415 | // eat up and down keys to be consistent | ||
416 | handled = TRUE; | ||
417 | break; | ||
418 | case KEY_LEFT: | ||
419 | setCurSliderValue(getCurSliderValue() - getIncrement()); | ||
420 | onCommit(); | ||
421 | handled = TRUE; | ||
422 | break; | ||
423 | case KEY_RIGHT: | ||
424 | setCurSliderValue(getCurSliderValue() + getIncrement()); | ||
425 | onCommit(); | ||
426 | handled = TRUE; | ||
427 | break; | ||
428 | default: | ||
429 | break; | ||
430 | } | ||
431 | } | ||
432 | return handled; | ||
433 | } | ||
434 | |||
435 | void LLMultiSlider::draw() | ||
436 | { | ||
437 | LLColor4 curThumbColor; | ||
438 | |||
439 | std::map<LLString, LLRect>::iterator mIt; | ||
440 | std::map<LLString, LLRect>::iterator curSldrIt; | ||
441 | if( getVisible() ) | ||
442 | { | ||
443 | // Draw background and thumb. | ||
444 | |||
445 | // drawing solids requires texturing be disabled | ||
446 | LLGLSNoTexture no_texture; | ||
447 | |||
448 | LLRect rect(mDragStartThumbRect); | ||
449 | |||
450 | F32 opacity = getEnabled() ? 1.f : 0.3f; | ||
451 | |||
452 | // Track | ||
453 | LLUUID thumb_image_id; | ||
454 | thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga")); | ||
455 | LLPointer<LLImageGL> thumb_imagep(LLUI::sImageProvider->getUIImageByID(thumb_image_id)->getImage()); | ||
456 | |||
457 | S32 height_offset = (getRect().getHeight() - MULTI_TRACK_HEIGHT) / 2; | ||
458 | LLRect track_rect(0, getRect().getHeight() - height_offset, getRect().getWidth(), height_offset ); | ||
459 | |||
460 | |||
461 | if(mDrawTrack) | ||
462 | { | ||
463 | track_rect.stretch(-1); | ||
464 | gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(), | ||
465 | thumb_imagep, mTrackColor % opacity); | ||
466 | } | ||
467 | |||
468 | // if we're supposed to use a drawn triangle | ||
469 | // simple gl call for the triangle | ||
470 | if(mUseTriangle) { | ||
471 | |||
472 | for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { | ||
473 | |||
474 | gl_triangle_2d( | ||
475 | mIt->second.mLeft - EXTRA_TRIANGLE_WIDTH, | ||
476 | mIt->second.mTop + EXTRA_TRIANGLE_HEIGHT, | ||
477 | mIt->second.mRight + EXTRA_TRIANGLE_WIDTH, | ||
478 | mIt->second.mTop + EXTRA_TRIANGLE_HEIGHT, | ||
479 | mIt->second.mLeft + mIt->second.getWidth() / 2, | ||
480 | mIt->second.mBottom - EXTRA_TRIANGLE_HEIGHT, | ||
481 | mTriangleColor, TRUE); | ||
482 | } | ||
483 | } | ||
484 | else if (!thumb_imagep) | ||
485 | { | ||
486 | // draw all the thumbs | ||
487 | curSldrIt = mThumbRects.end(); | ||
488 | for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { | ||
489 | |||
490 | // choose the color | ||
491 | curThumbColor = mThumbCenterColor; | ||
492 | if(mIt->first == mCurSlider) { | ||
493 | |||
494 | curSldrIt = mIt; | ||
495 | continue; | ||
496 | //curThumbColor = mThumbCenterSelectedColor; | ||
497 | } | ||
498 | |||
499 | // the draw command | ||
500 | gl_rect_2d(mIt->second, curThumbColor, TRUE); | ||
501 | } | ||
502 | |||
503 | // now draw the current slider | ||
504 | if(curSldrIt != mThumbRects.end()) { | ||
505 | gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor, TRUE); | ||
506 | } | ||
507 | |||
508 | // and draw the drag start | ||
509 | if (gFocusMgr.getMouseCapture() == this) | ||
510 | { | ||
511 | gl_rect_2d(mDragStartThumbRect, mThumbCenterColor % opacity, FALSE); | ||
512 | } | ||
513 | } | ||
514 | else if( gFocusMgr.getMouseCapture() == this ) | ||
515 | { | ||
516 | // draw drag start | ||
517 | gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, | ||
518 | mDragStartThumbRect.mBottom, 16, 16, | ||
519 | mDragStartThumbRect.getWidth(), | ||
520 | mDragStartThumbRect.getHeight(), | ||
521 | thumb_imagep, mThumbCenterColor % 0.3f, TRUE); | ||
522 | |||
523 | // draw the highlight | ||
524 | if (hasFocus()) | ||
525 | { | ||
526 | F32 lerp_amt = gFocusMgr.getFocusFlashAmt(); | ||
527 | LLRect highlight_rect = mThumbRects[mCurSlider]; | ||
528 | highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt))); | ||
529 | gl_draw_scaled_image_with_border(highlight_rect.mLeft, | ||
530 | highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), | ||
531 | highlight_rect.getHeight(), | ||
532 | thumb_imagep, gFocusMgr.getFocusColor()); | ||
533 | } | ||
534 | |||
535 | // draw the thumbs | ||
536 | curSldrIt = mThumbRects.end(); | ||
537 | for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { | ||
538 | |||
539 | // choose the color | ||
540 | curThumbColor = mThumbCenterColor; | ||
541 | if(mIt->first == mCurSlider) { | ||
542 | // don't draw now, draw last | ||
543 | curSldrIt = mIt; | ||
544 | continue; | ||
545 | } | ||
546 | |||
547 | // the draw command | ||
548 | gl_draw_scaled_image_with_border( | ||
549 | mIt->second.mLeft, | ||
550 | mIt->second.mBottom, 16, 16, | ||
551 | mIt->second.getWidth(), | ||
552 | mIt->second.getHeight(), thumb_imagep, | ||
553 | curThumbColor, TRUE); | ||
554 | } | ||
555 | |||
556 | // draw cur slider last | ||
557 | if(curSldrIt != mThumbRects.end()) { | ||
558 | gl_draw_scaled_image_with_border( | ||
559 | curSldrIt->second.mLeft, | ||
560 | curSldrIt->second.mBottom, 16, 16, | ||
561 | curSldrIt->second.getWidth(), | ||
562 | curSldrIt->second.getHeight(), thumb_imagep, | ||
563 | mThumbCenterSelectedColor, TRUE); | ||
564 | } | ||
565 | |||
566 | } | ||
567 | else | ||
568 | { | ||
569 | // draw highlight | ||
570 | if (hasFocus()) | ||
571 | { | ||
572 | F32 lerp_amt = gFocusMgr.getFocusFlashAmt(); | ||
573 | LLRect highlight_rect = mThumbRects[mCurSlider]; | ||
574 | highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt))); | ||
575 | gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(), | ||
576 | thumb_imagep, gFocusMgr.getFocusColor()); | ||
577 | } | ||
578 | |||
579 | // draw thumbs | ||
580 | curSldrIt = mThumbRects.end(); | ||
581 | for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) { | ||
582 | |||
583 | // choose the color | ||
584 | curThumbColor = mThumbCenterColor; | ||
585 | if(mIt->first == mCurSlider) { | ||
586 | curSldrIt = mIt; | ||
587 | continue; | ||
588 | //curThumbColor = mThumbCenterSelectedColor; | ||
589 | } | ||
590 | |||
591 | // the draw command | ||
592 | gl_draw_scaled_image_with_border( | ||
593 | mIt->second.mLeft, | ||
594 | mIt->second.mBottom, 16, 16, | ||
595 | mIt->second.getWidth(), | ||
596 | mIt->second.getHeight(), thumb_imagep, | ||
597 | curThumbColor % opacity, TRUE); | ||
598 | } | ||
599 | |||
600 | if(curSldrIt != mThumbRects.end()) { | ||
601 | gl_draw_scaled_image_with_border( | ||
602 | curSldrIt->second.mLeft, | ||
603 | curSldrIt->second.mBottom, 16, 16, | ||
604 | curSldrIt->second.getWidth(), | ||
605 | curSldrIt->second.getHeight(), thumb_imagep, | ||
606 | mThumbCenterSelectedColor % opacity, TRUE); | ||
607 | } | ||
608 | } | ||
609 | |||
610 | LLUICtrl::draw(); | ||
611 | } | ||
612 | } | ||
613 | |||
614 | // virtual | ||
615 | LLXMLNodePtr LLMultiSlider::getXML(bool save_children) const | ||
616 | { | ||
617 | LLXMLNodePtr node = LLUICtrl::getXML(); | ||
618 | |||
619 | node->createChild("initial_val", TRUE)->setFloatValue(getInitialValue()); | ||
620 | node->createChild("min_val", TRUE)->setFloatValue(getMinValue()); | ||
621 | node->createChild("max_val", TRUE)->setFloatValue(getMaxValue()); | ||
622 | node->createChild("increment", TRUE)->setFloatValue(getIncrement()); | ||
623 | |||
624 | return node; | ||
625 | } | ||
626 | |||
627 | |||
628 | //static | ||
629 | LLView* LLMultiSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) | ||
630 | { | ||
631 | LLString name("multi_slider_bar"); | ||
632 | node->getAttributeString("name", name); | ||
633 | |||
634 | LLRect rect; | ||
635 | createRect(node, rect, parent, LLRect()); | ||
636 | |||
637 | F32 initial_value = 0.f; | ||
638 | node->getAttributeF32("initial_val", initial_value); | ||
639 | |||
640 | F32 min_value = 0.f; | ||
641 | node->getAttributeF32("min_val", min_value); | ||
642 | |||
643 | F32 max_value = 1.f; | ||
644 | node->getAttributeF32("max_val", max_value); | ||
645 | |||
646 | F32 increment = 0.1f; | ||
647 | node->getAttributeF32("increment", increment); | ||
648 | |||
649 | S32 max_sliders = 1; | ||
650 | node->getAttributeS32("max_sliders", max_sliders); | ||
651 | |||
652 | BOOL allow_overlap = FALSE; | ||
653 | node->getAttributeBOOL("allow_overlap", allow_overlap); | ||
654 | |||
655 | BOOL draw_track = TRUE; | ||
656 | node->getAttributeBOOL("draw_track", draw_track); | ||
657 | |||
658 | BOOL use_triangle = FALSE; | ||
659 | node->getAttributeBOOL("use_triangle", use_triangle); | ||
660 | |||
661 | LLMultiSlider* multiSlider = new LLMultiSlider(name, | ||
662 | rect, | ||
663 | NULL, | ||
664 | NULL, | ||
665 | initial_value, | ||
666 | min_value, | ||
667 | max_value, | ||
668 | increment, | ||
669 | max_sliders, | ||
670 | allow_overlap, | ||
671 | draw_track, | ||
672 | use_triangle); | ||
673 | |||
674 | multiSlider->initFromXML(node, parent); | ||
675 | |||
676 | return multiSlider; | ||
677 | } | ||