diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llui/llslider.cpp | 371 |
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 | |||
40 | const S32 THUMB_WIDTH = 8; | ||
41 | const S32 TRACK_HEIGHT = 6; | ||
42 | |||
43 | LLSlider::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 | |||
78 | EWidgetType LLSlider::getWidgetType() const | ||
79 | { | ||
80 | return WIDGET_TYPE_SLIDER_BAR; | ||
81 | } | ||
82 | |||
83 | LLString LLSlider::getWidgetTag() const | ||
84 | { | ||
85 | return LL_SLIDER_TAG; | ||
86 | } | ||
87 | |||
88 | void 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 | |||
113 | F32 LLSlider::getValueF32() const | ||
114 | { | ||
115 | return mValue; | ||
116 | } | ||
117 | |||
118 | BOOL 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 | |||
143 | BOOL 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 | |||
166 | BOOL 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 | |||
205 | BOOL 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 | |||
234 | void 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 | ||
324 | LLXMLNodePtr 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 | ||
338 | LLView* 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 | } | ||