aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/llslider.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llui/llslider.cpp371
1 files changed, 371 insertions, 0 deletions
diff --git a/linden/indra/llui/llslider.cpp b/linden/indra/llui/llslider.cpp
new file mode 100644
index 0000000..20d77bf
--- /dev/null
+++ b/linden/indra/llui/llslider.cpp
@@ -0,0 +1,371 @@
1/**
2 * @file llslider.cpp
3 * @brief LLSlider 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 "llslider.h"
31#include "llui.h"
32
33#include "llgl.h"
34#include "llwindow.h"
35#include "llfocusmgr.h"
36#include "llkeyboard.h" // for the MASK constants
37#include "llcontrol.h"
38#include "llimagegl.h"
39
40const S32 THUMB_WIDTH = 8;
41const S32 TRACK_HEIGHT = 6;
42
43LLSlider::LLSlider(
44 const LLString& name,
45 const LLRect& rect,
46 void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata),
47 void* callback_userdata,
48 F32 initial_value,
49 F32 min_value,
50 F32 max_value,
51 F32 increment,
52 const LLString& control_name)
53 :
54 LLUICtrl( name, rect, TRUE, on_commit_callback, callback_userdata,
55 FOLLOWS_LEFT | FOLLOWS_TOP),
56 mValue( initial_value ),
57 mInitialValue( initial_value ),
58 mMinValue( min_value ),
59 mMaxValue( max_value ),
60 mIncrement( increment ),
61 mMouseOffset( 0 ),
62 mDragStartThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
63 mThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
64 mTrackColor( LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ),
65 mThumbOutlineColor( LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ),
66 mThumbCenterColor( LLUI::sColorsGroup->getColor( "SliderThumbCenterColor" ) ),
67 mDisabledThumbColor(LLUI::sColorsGroup->getColor( "SliderDisabledThumbColor" ) ),
68 mMouseDownCallback( NULL ),
69 mMouseUpCallback( NULL )
70{
71 // prperly handle setting the starting thumb rect
72 // do it this way to handle both the operating-on-settings
73 // and standalone ways of using this
74 setControlName(control_name, NULL);
75 setValue(getValueF32());
76}
77
78EWidgetType LLSlider::getWidgetType() const
79{
80 return WIDGET_TYPE_SLIDER_BAR;
81}
82
83LLString LLSlider::getWidgetTag() const
84{
85 return LL_SLIDER_TAG;
86}
87
88void LLSlider::setValue(F32 value, BOOL from_event)
89{
90 value = llclamp( value, mMinValue, mMaxValue );
91
92 // Round to nearest increment (bias towards rounding down)
93 value -= mMinValue;
94 value += mIncrement/2.0001f;
95 value -= fmod(value, mIncrement);
96 mValue = mMinValue + value;
97
98 if (!from_event)
99 {
100 setControlValue(mValue);
101 }
102
103 F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
104
105 S32 left_edge = THUMB_WIDTH/2;
106 S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
107
108 S32 x = left_edge + S32( t * (right_edge - left_edge) );
109 mThumbRect.mLeft = x - (THUMB_WIDTH/2);
110 mThumbRect.mRight = x + (THUMB_WIDTH/2);
111}
112
113F32 LLSlider::getValueF32() const
114{
115 return mValue;
116}
117
118BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask)
119{
120 if( gFocusMgr.getMouseCapture() == this )
121 {
122 S32 left_edge = THUMB_WIDTH/2;
123 S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
124
125 x += mMouseOffset;
126 x = llclamp( x, left_edge, right_edge );
127
128 F32 t = F32(x - left_edge) / (right_edge - left_edge);
129 setValue(t * (mMaxValue - mMinValue) + mMinValue );
130 onCommit();
131
132 getWindow()->setCursor(UI_CURSOR_ARROW);
133 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;
134 }
135 else
136 {
137 getWindow()->setCursor(UI_CURSOR_ARROW);
138 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;
139 }
140 return TRUE;
141}
142
143BOOL LLSlider::handleMouseUp(S32 x, S32 y, MASK mask)
144{
145 BOOL handled = FALSE;
146
147 if( gFocusMgr.getMouseCapture() == this )
148 {
149 gFocusMgr.setMouseCapture( NULL, NULL );
150
151 if( mMouseUpCallback )
152 {
153 mMouseUpCallback( this, mCallbackUserData );
154 }
155 handled = TRUE;
156 make_ui_sound("UISndClickRelease");
157 }
158 else
159 {
160 handled = TRUE;
161 }
162
163 return handled;
164}
165
166BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
167{
168 // only do sticky-focus on non-chrome widgets
169 if (!getIsChrome())
170 {
171 setFocus(TRUE);
172 }
173 if( mMouseDownCallback )
174 {
175 mMouseDownCallback( this, mCallbackUserData );
176 }
177
178 if (MASK_CONTROL & mask) // if CTRL is modifying
179 {
180 setValue(mInitialValue);
181 onCommit();
182 }
183 else
184 {
185 // Find the offset of the actual mouse location from the center of the thumb.
186 if (mThumbRect.pointInRect(x,y))
187 {
188 mMouseOffset = (mThumbRect.mLeft + THUMB_WIDTH/2) - x;
189 }
190 else
191 {
192 mMouseOffset = 0;
193 }
194
195 // Start dragging the thumb
196 // No handler needed for focus lost since this class has no state that depends on it.
197 gFocusMgr.setMouseCapture( this, NULL );
198 mDragStartThumbRect = mThumbRect;
199 }
200 make_ui_sound("UISndClick");
201
202 return TRUE;
203}
204
205BOOL LLSlider::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
206{
207 BOOL handled = FALSE;
208 if( getVisible() && mEnabled && !called_from_parent )
209 {
210 switch(key)
211 {
212 case KEY_UP:
213 case KEY_DOWN:
214 // eat up and down keys to be consistent
215 handled = TRUE;
216 break;
217 case KEY_LEFT:
218 setValue(getValueF32() - getIncrement());
219 onCommit();
220 handled = TRUE;
221 break;
222 case KEY_RIGHT:
223 setValue(getValueF32() + getIncrement());
224 onCommit();
225 handled = TRUE;
226 break;
227 default:
228 break;
229 }
230 }
231 return handled;
232}
233
234void LLSlider::draw()
235{
236 if( getVisible() )
237 {
238 // Draw background and thumb.
239
240 // drawing solids requires texturing be disabled
241 LLGLSNoTexture no_texture;
242
243 LLRect rect(mDragStartThumbRect);
244
245 F32 opacity = mEnabled ? 1.f : 0.3f;
246
247 // Track
248
249 LLUUID thumb_image_id;
250 thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga"));
251 LLImageGL* thumb_imagep = LLUI::sImageProvider->getUIImageByID(thumb_image_id);
252
253 S32 height_offset = (mRect.getHeight() - TRACK_HEIGHT) / 2;
254 LLRect track_rect(0, mRect.getHeight() - height_offset, mRect.getWidth(), height_offset );
255
256 track_rect.stretch(-1);
257 gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(),
258 thumb_imagep, mTrackColor % opacity);
259 //gl_rect_2d( track_rect, mThumbOutlineColor % opacity );
260
261 if (!thumb_imagep)
262 {
263 gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE);
264 if (gFocusMgr.getMouseCapture() == this)
265 {
266 gl_rect_2d(mDragStartThumbRect, mThumbCenterColor % opacity, FALSE);
267 }
268 }
269 else if( gFocusMgr.getMouseCapture() == this )
270 {
271 gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, 16, 16, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(),
272 thumb_imagep, mThumbCenterColor % 0.3f, TRUE);
273
274 if (hasFocus())
275 {
276 F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
277 LLRect highlight_rect = mThumbRect;
278 highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
279 gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
280 thumb_imagep, gFocusMgr.getFocusColor());
281 }
282
283
284 gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(),
285 thumb_imagep, mThumbOutlineColor, TRUE);
286
287 //// Start Thumb
288 //gl_rect_2d( mDragStartThumbRect, mThumbOutlineColor % 0.3f );
289 //rect.stretch(-1);
290 //gl_rect_2d( rect, mThumbCenterColor % 0.3f );
291
292 //// Thumb
293 //gl_rect_2d( mThumbRect, mThumbOutlineColor );
294 }
295 else
296 {
297 if (hasFocus())
298 {
299 F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
300 LLRect highlight_rect = mThumbRect;
301 highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
302 gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
303 thumb_imagep, gFocusMgr.getFocusColor());
304 }
305
306 gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(),
307 thumb_imagep, mThumbCenterColor % opacity, TRUE);
308 //rect = mThumbRect;
309
310 //gl_rect_2d( mThumbRect, mThumbOutlineColor % opacity );
311 //
312 //rect.stretch(-1);
313
314 //// Thumb
315 //gl_rect_2d( rect, mThumbCenterColor % opacity );
316
317 }
318
319 LLUICtrl::draw();
320 }
321}
322
323// virtual
324LLXMLNodePtr LLSlider::getXML(bool save_children) const
325{
326 LLXMLNodePtr node = LLUICtrl::getXML();
327
328 node->createChild("initial_val", TRUE)->setFloatValue(getInitialValue());
329 node->createChild("min_val", TRUE)->setFloatValue(getMinValue());
330 node->createChild("max_val", TRUE)->setFloatValue(getMaxValue());
331 node->createChild("increment", TRUE)->setFloatValue(getIncrement());
332
333 return node;
334}
335
336
337//static
338LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
339{
340 LLString name("slider_bar");
341 node->getAttributeString("name", name);
342
343 LLRect rect;
344 createRect(node, rect, parent, LLRect());
345
346 F32 initial_value = 0.f;
347 node->getAttributeF32("initial_val", initial_value);
348
349 F32 min_value = 0.f;
350 node->getAttributeF32("min_val", min_value);
351
352 F32 max_value = 1.f;
353 node->getAttributeF32("max_val", max_value);
354
355 F32 increment = 0.1f;
356 node->getAttributeF32("increment", increment);
357
358
359 LLSlider* slider = new LLSlider(name,
360 rect,
361 NULL,
362 NULL,
363 initial_value,
364 min_value,
365 max_value,
366 increment);
367
368 slider->initFromXML(node, parent);
369
370 return slider;
371}