PageRenderTime 44ms CodeModel.GetById 1ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llslider.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 384 lines | 294 code | 51 blank | 39 comment | 37 complexity | 97a0e6e13dcfa227c5440a8a7c016ce0 MD5 | raw file
  1/** 
  2 * @file llslider.cpp
  3 * @brief LLSlider base class
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28
 29#include "llslider.h"
 30#include "llui.h"
 31
 32#include "llgl.h"
 33#include "llwindow.h"
 34#include "llfocusmgr.h"
 35#include "llkeyboard.h"			// for the MASK constants
 36#include "llcontrol.h"
 37#include "lluictrlfactory.h"
 38
 39static LLDefaultChildRegistry::Register<LLSlider> r1("slider_bar");
 40//FIXME: make this into an unregistered template so that code constructed sliders don't
 41// have ambigious template lookup problem
 42
 43LLSlider::Params::Params()
 44:	orientation ("orientation", std::string ("horizontal")),
 45	track_color("track_color"),
 46	thumb_outline_color("thumb_outline_color"),
 47	thumb_center_color("thumb_center_color"),
 48	thumb_image("thumb_image"),
 49	thumb_image_pressed("thumb_image_pressed"),
 50	thumb_image_disabled("thumb_image_disabled"),
 51	track_image_horizontal("track_image_horizontal"),
 52	track_image_vertical("track_image_vertical"),
 53	track_highlight_horizontal_image("track_highlight_horizontal_image"),
 54	track_highlight_vertical_image("track_highlight_vertical_image"),
 55	mouse_down_callback("mouse_down_callback"),
 56	mouse_up_callback("mouse_up_callback")
 57{}
 58
 59LLSlider::LLSlider(const LLSlider::Params& p)
 60:	LLF32UICtrl(p),
 61	mMouseOffset( 0 ),
 62	mOrientation ((p.orientation() == "horizontal") ? HORIZONTAL : VERTICAL),
 63	mTrackColor(p.track_color()),
 64	mThumbOutlineColor(p.thumb_outline_color()),
 65	mThumbCenterColor(p.thumb_center_color()),
 66	mThumbImage(p.thumb_image),
 67	mThumbImagePressed(p.thumb_image_pressed),
 68	mThumbImageDisabled(p.thumb_image_disabled),
 69	mTrackImageHorizontal(p.track_image_horizontal),
 70	mTrackImageVertical(p.track_image_vertical),
 71	mTrackHighlightHorizontalImage(p.track_highlight_horizontal_image),
 72	mTrackHighlightVerticalImage(p.track_highlight_vertical_image),
 73	mMouseDownSignal(NULL),
 74	mMouseUpSignal(NULL)
 75{
 76    mViewModel->setValue(p.initial_value);
 77	updateThumbRect();
 78	mDragStartThumbRect = mThumbRect;
 79	setControlName(p.control_name, NULL);
 80	setValue(getValueF32());
 81	
 82	if (p.mouse_down_callback.isProvided())
 83	{
 84		setMouseDownCallback(initCommitCallback(p.mouse_down_callback));
 85	}
 86	if (p.mouse_up_callback.isProvided())
 87	{
 88		setMouseUpCallback(initCommitCallback(p.mouse_up_callback));
 89	}
 90}
 91
 92LLSlider::~LLSlider()
 93{
 94	delete mMouseDownSignal;
 95	delete mMouseUpSignal;
 96}
 97
 98void LLSlider::setValue(F32 value, BOOL from_event)
 99{
100	value = llclamp( value, mMinValue, mMaxValue );
101
102	// Round to nearest increment (bias towards rounding down)
103	value -= mMinValue;
104	value += mIncrement/2.0001f;
105	value -= fmod(value, mIncrement);
106	value += mMinValue;
107
108	if (!from_event && getValueF32() != value)
109	{
110		setControlValue(value);
111	}
112
113    LLF32UICtrl::setValue(value);
114	updateThumbRect();
115}
116
117void LLSlider::updateThumbRect()
118{
119	const S32 DEFAULT_THUMB_SIZE = 16;
120	F32 t = (getValueF32() - mMinValue) / (mMaxValue - mMinValue);
121
122	S32 thumb_width = mThumbImage ? mThumbImage->getWidth() : DEFAULT_THUMB_SIZE;
123	S32 thumb_height = mThumbImage ? mThumbImage->getHeight() : DEFAULT_THUMB_SIZE;
124
125	if ( mOrientation == HORIZONTAL )
126	{
127		S32 left_edge = (thumb_width / 2);
128		S32 right_edge = getRect().getWidth() - (thumb_width / 2);
129
130		S32 x = left_edge + S32( t * (right_edge - left_edge) );
131		mThumbRect.mLeft = x - (thumb_width / 2);
132		mThumbRect.mRight = mThumbRect.mLeft + thumb_width;
133		mThumbRect.mBottom = getLocalRect().getCenterY() - (thumb_height / 2);
134		mThumbRect.mTop = mThumbRect.mBottom + thumb_height;
135	}
136	else
137	{
138		S32 top_edge = (thumb_height / 2);
139		S32 bottom_edge = getRect().getHeight() - (thumb_height / 2);
140
141		S32 y = top_edge + S32( t * (bottom_edge - top_edge) );
142		mThumbRect.mLeft = getLocalRect().getCenterX() - (thumb_width / 2);
143		mThumbRect.mRight = mThumbRect.mLeft + thumb_width;
144		mThumbRect.mBottom = y  - (thumb_height / 2);
145		mThumbRect.mTop = mThumbRect.mBottom + thumb_height;
146	}
147}
148
149
150void LLSlider::setValueAndCommit(F32 value)
151{
152	F32 old_value = getValueF32();
153	setValue(value);
154
155	if (getValueF32() != old_value)
156	{
157		onCommit();
158	}
159}
160
161
162BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask)
163{
164	if( hasMouseCapture() )
165	{
166		if ( mOrientation == HORIZONTAL )
167		{
168			S32 thumb_half_width = mThumbImage->getWidth()/2;
169			S32 left_edge = thumb_half_width;
170			S32 right_edge = getRect().getWidth() - (thumb_half_width);
171
172			x += mMouseOffset;
173			x = llclamp( x, left_edge, right_edge );
174
175			F32 t = F32(x - left_edge) / (right_edge - left_edge);
176			setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue );
177		}
178		else // mOrientation == VERTICAL
179		{
180			S32 thumb_half_height = mThumbImage->getHeight()/2;
181			S32 top_edge = thumb_half_height;
182			S32 bottom_edge = getRect().getHeight() - (thumb_half_height);
183
184			y += mMouseOffset;
185			y = llclamp(y, top_edge, bottom_edge);
186
187			F32 t = F32(y - top_edge) / (bottom_edge - top_edge);
188			setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue );
189		}
190		getWindow()->setCursor(UI_CURSOR_ARROW);
191		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;
192	}
193	else
194	{
195		getWindow()->setCursor(UI_CURSOR_ARROW);
196		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;		
197	}
198	return TRUE;
199}
200
201BOOL LLSlider::handleMouseUp(S32 x, S32 y, MASK mask)
202{
203	BOOL handled = FALSE;
204
205	if( hasMouseCapture() )
206	{
207		gFocusMgr.setMouseCapture( NULL );
208
209		if (mMouseUpSignal)
210			(*mMouseUpSignal)( this, getValueF32() );
211
212		handled = TRUE;
213		make_ui_sound("UISndClickRelease");
214	}
215	else
216	{
217		handled = TRUE;
218	}
219
220	return handled;
221}
222
223BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
224{
225	// only do sticky-focus on non-chrome widgets
226	if (!getIsChrome())
227	{
228		setFocus(TRUE);
229	}
230	if (mMouseDownSignal)
231		(*mMouseDownSignal)( this, getValueF32() );
232
233	if (MASK_CONTROL & mask) // if CTRL is modifying
234	{
235		setValueAndCommit(mInitialValue);
236	}
237	else
238	{
239		// Find the offset of the actual mouse location from the center of the thumb.
240		if (mThumbRect.pointInRect(x,y))
241		{
242			mMouseOffset = (mOrientation == HORIZONTAL)
243				? (mThumbRect.mLeft + mThumbImage->getWidth()/2) - x
244				: (mThumbRect.mBottom + mThumbImage->getHeight()/2) - y;
245		}
246		else
247		{
248			mMouseOffset = 0;
249		}
250
251		// Start dragging the thumb
252		// No handler needed for focus lost since this class has no state that depends on it.
253		gFocusMgr.setMouseCapture( this );  
254		mDragStartThumbRect = mThumbRect;				
255	}
256	make_ui_sound("UISndClick");
257
258	return TRUE;
259}
260
261BOOL LLSlider::handleKeyHere(KEY key, MASK mask)
262{
263	BOOL handled = FALSE;
264	switch(key)
265	{
266	case KEY_DOWN:
267	case KEY_LEFT:
268		setValueAndCommit(getValueF32() - getIncrement());
269		handled = TRUE;
270		break;
271	case KEY_UP:
272	case KEY_RIGHT:
273		setValueAndCommit(getValueF32() + getIncrement());
274		handled = TRUE;
275		break;
276	default:
277		break;
278	}
279	return handled;
280}
281
282BOOL LLSlider::handleScrollWheel(S32 x, S32 y, S32 clicks)
283{
284	if ( mOrientation == VERTICAL )
285	{
286		F32 new_val = getValueF32() - clicks * getIncrement();
287		setValueAndCommit(new_val);
288		return TRUE;
289	}
290	return LLF32UICtrl::handleScrollWheel(x,y,clicks);
291}
292
293void LLSlider::draw()
294{
295	F32 alpha = getDrawContext().mAlpha;
296
297	// since thumb image might still be decoding, need thumb to accomodate image size
298	updateThumbRect();
299
300	// Draw background and thumb.
301
302	// drawing solids requires texturing be disabled
303	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
304
305	// Track
306	LLPointer<LLUIImage>& trackImage = ( mOrientation == HORIZONTAL )
307		? mTrackImageHorizontal
308		: mTrackImageVertical;
309
310	LLPointer<LLUIImage>& trackHighlightImage = ( mOrientation == HORIZONTAL )
311		? mTrackHighlightHorizontalImage
312		: mTrackHighlightVerticalImage;
313
314	LLRect track_rect;
315	LLRect highlight_rect;
316
317	if ( mOrientation == HORIZONTAL )
318	{
319		track_rect.set(mThumbImage->getWidth() / 2,
320					   getLocalRect().getCenterY() + (trackImage->getHeight() / 2), 
321					   getRect().getWidth() - mThumbImage->getWidth() / 2,
322					   getLocalRect().getCenterY() - (trackImage->getHeight() / 2) );
323		highlight_rect.set(track_rect.mLeft, track_rect.mTop, mThumbRect.getCenterX(), track_rect.mBottom);
324	}
325	else
326	{
327		track_rect.set(getLocalRect().getCenterX() - (trackImage->getWidth() / 2),
328					   getRect().getHeight(),
329					   getLocalRect().getCenterX() + (trackImage->getWidth() / 2),
330					   0);
331		highlight_rect.set(track_rect.mLeft, track_rect.mTop, track_rect.mRight, track_rect.mBottom);
332	}
333
334	trackImage->draw(track_rect, LLColor4::white % alpha);
335	trackHighlightImage->draw(highlight_rect, LLColor4::white % alpha);
336
337	// Thumb
338	if (hasFocus())
339	{
340		// Draw focus highlighting.
341		mThumbImage->drawBorder(mThumbRect, gFocusMgr.getFocusColor() % alpha, gFocusMgr.getFocusFlashWidth());
342	}
343
344	if( hasMouseCapture() ) // currently clicking on slider
345	{
346		// Show ghost where thumb was before dragging began.
347		if (mThumbImage.notNull())
348		{
349			mThumbImage->draw(mDragStartThumbRect, mThumbCenterColor.get() % (0.3f * alpha));
350		}
351		if (mThumbImagePressed.notNull())
352		{
353			mThumbImagePressed->draw(mThumbRect, mThumbOutlineColor % alpha);
354		}
355	}
356	else if (!isInEnabledChain())
357	{
358		if (mThumbImageDisabled.notNull())
359		{
360			mThumbImageDisabled->draw(mThumbRect, mThumbCenterColor % alpha);
361		}
362	}
363	else
364	{
365		if (mThumbImage.notNull())
366		{
367			mThumbImage->draw(mThumbRect, mThumbCenterColor % alpha);
368		}
369	}
370	
371	LLUICtrl::draw();
372}
373
374boost::signals2::connection LLSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb ) 
375{ 
376	if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
377	return mMouseDownSignal->connect(cb); 
378}
379
380boost::signals2::connection LLSlider::setMouseUpCallback(	const commit_signal_t::slot_type& cb )   
381{ 
382	if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t();
383	return mMouseUpSignal->connect(cb); 
384}