PageRenderTime 67ms CodeModel.GetById 18ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llscrollbar.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 644 lines | 477 code | 97 blank | 70 comment | 87 complexity | d1e7eaafd33f778726f9008779d55550 MD5 | raw file
  1/** 
  2 * @file llscrollbar.cpp
  3 * @brief Scrollbar UI widget
  4 *
  5 * $LicenseInfo:firstyear=2001&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 "llscrollbar.h"
 30
 31#include "llmath.h"
 32#include "lltimer.h"
 33#include "v3color.h"
 34
 35#include "llbutton.h"
 36#include "llcriticaldamp.h"
 37#include "llkeyboard.h"
 38#include "llui.h"
 39#include "llfocusmgr.h"
 40#include "llwindow.h"
 41#include "llcontrol.h"
 42#include "llrender.h"
 43#include "lluictrlfactory.h"
 44
 45static LLDefaultChildRegistry::Register<LLScrollbar> register_scrollbar("scroll_bar");
 46
 47LLScrollbar::Params::Params()
 48:	orientation ("orientation", HORIZONTAL),
 49	doc_size ("doc_size", 0),
 50	doc_pos ("doc_pos", 0),
 51	page_size ("page_size", 0),
 52	step_size ("step_size", 1),
 53	thumb_image_vertical("thumb_image_vertical"),
 54	thumb_image_horizontal("thumb_image_horizontal"),
 55	track_image_vertical("track_image_vertical"),
 56	track_image_horizontal("track_image_horizontal"),
 57	track_color("track_color"),
 58	thumb_color("thumb_color"),
 59	thickness("thickness"),
 60	up_button("up_button"),
 61	down_button("down_button"),
 62	left_button("left_button"),
 63	right_button("right_button"),
 64	bg_visible("bg_visible", false),
 65	bg_color("bg_color", LLColor4::black)
 66{}
 67
 68LLScrollbar::LLScrollbar(const Params & p)
 69:		LLUICtrl(p),
 70		mChangeCallback( p.change_callback() ),
 71		mOrientation( p.orientation ),
 72		mDocSize( p.doc_size ),
 73		mDocPos( p.doc_pos ),
 74		mPageSize( p.page_size ),
 75		mStepSize( p.step_size ),
 76		mDocChanged(FALSE),
 77		mDragStartX( 0 ),
 78		mDragStartY( 0 ),
 79		mHoverGlowStrength(0.15f),
 80		mCurGlowStrength(0.f),
 81		mTrackColor( p.track_color() ),
 82		mThumbColor ( p.thumb_color() ),
 83		mThumbImageV(p.thumb_image_vertical),
 84		mThumbImageH(p.thumb_image_horizontal),
 85		mTrackImageV(p.track_image_vertical),
 86		mTrackImageH(p.track_image_horizontal),
 87		mThickness(p.thickness.isProvided() ? p.thickness : LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize")),
 88		mBGVisible(p.bg_visible),
 89		mBGColor(p.bg_color)
 90{
 91	updateThumbRect();
 92	
 93	// Page up and page down buttons
 94	LLRect line_up_rect;
 95	LLRect line_down_rect;
 96
 97	if( VERTICAL == mOrientation )
 98	{
 99		line_up_rect.setLeftTopAndSize( 0, getRect().getHeight(), mThickness, mThickness );
100		line_down_rect.setOriginAndSize( 0, 0, mThickness, mThickness );
101	}
102	else // HORIZONTAL
103	{
104		line_up_rect.setOriginAndSize( 0, 0, mThickness, mThickness );
105		line_down_rect.setOriginAndSize( getRect().getWidth() - mThickness, 0, mThickness, mThickness );
106	}
107
108	LLButton::Params up_btn(mOrientation == VERTICAL ? p.up_button : p.left_button);
109	up_btn.name(std::string("Line Up"));
110	up_btn.rect(line_up_rect);
111	up_btn.click_callback.function(boost::bind(&LLScrollbar::onLineUpBtnPressed, this, _2));
112	up_btn.mouse_held_callback.function(boost::bind(&LLScrollbar::onLineUpBtnPressed, this, _2));
113	up_btn.tab_stop(false);
114	up_btn.follows.flags = (mOrientation == VERTICAL ? (FOLLOWS_RIGHT | FOLLOWS_TOP) : (FOLLOWS_LEFT | FOLLOWS_BOTTOM));
115
116	addChild(LLUICtrlFactory::create<LLButton>(up_btn));
117
118	LLButton::Params down_btn(mOrientation == VERTICAL ? p.down_button : p.right_button);
119	down_btn.name(std::string("Line Down"));
120	down_btn.rect(line_down_rect);
121	down_btn.follows.flags(FOLLOWS_RIGHT|FOLLOWS_BOTTOM);
122	down_btn.click_callback.function(boost::bind(&LLScrollbar::onLineDownBtnPressed, this, _2));
123	down_btn.mouse_held_callback.function(boost::bind(&LLScrollbar::onLineDownBtnPressed, this, _2));
124	down_btn.tab_stop(false);
125
126	addChild(LLUICtrlFactory::create<LLButton>(down_btn));
127}
128
129
130LLScrollbar::~LLScrollbar()
131{
132	// Children buttons killed by parent class
133}
134
135void LLScrollbar::setDocParams( S32 size, S32 pos )
136{
137	mDocSize = size;
138	setDocPos(pos);
139	mDocChanged = TRUE;
140
141	updateThumbRect();
142}
143
144// returns true if document position really changed
145bool LLScrollbar::setDocPos(S32 pos, BOOL update_thumb)
146{
147	pos = llclamp(pos, 0, getDocPosMax());
148	if (pos != mDocPos)
149	{
150		mDocPos = pos;
151		mDocChanged = TRUE;
152
153		if( mChangeCallback )
154		{
155			mChangeCallback( mDocPos, this );
156		}
157
158		if( update_thumb )
159		{
160			updateThumbRect();
161		}
162		return true;
163	}
164	return false;
165}
166
167void LLScrollbar::setDocSize(S32 size)
168{
169	if (size != mDocSize)
170	{
171		mDocSize = size;
172		setDocPos(mDocPos);
173		mDocChanged = TRUE;
174
175		updateThumbRect();
176	}
177}
178
179void LLScrollbar::setPageSize( S32 page_size )
180{
181	if (page_size != mPageSize)
182	{
183		mPageSize = page_size;
184		setDocPos(mDocPos);
185		mDocChanged = TRUE;
186
187		updateThumbRect();
188	}
189}
190
191BOOL LLScrollbar::isAtBeginning()
192{
193	return mDocPos == 0;
194}
195
196BOOL LLScrollbar::isAtEnd()
197{
198	return mDocPos == getDocPosMax();
199}
200
201
202void LLScrollbar::updateThumbRect()
203{
204//	llassert( 0 <= mDocSize );
205//	llassert( 0 <= mDocPos && mDocPos <= getDocPosMax() );
206	
207	const S32 THUMB_MIN_LENGTH = 16;
208
209	S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight();
210	S32 thumb_bg_length = llmax(0, window_length - 2 * mThickness);
211	S32 visible_lines = llmin( mDocSize, mPageSize );
212	S32 thumb_length = mDocSize ? llmin(llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH), thumb_bg_length) : thumb_bg_length;
213
214	S32 variable_lines = mDocSize - visible_lines;
215
216	if( mOrientation == LLScrollbar::VERTICAL )
217	{ 
218		S32 thumb_start_max = thumb_bg_length + mThickness;
219		S32 thumb_start_min = mThickness + THUMB_MIN_LENGTH;
220		S32 thumb_start = variable_lines ? llmin( llmax(thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_max;
221
222		mThumbRect.mLeft =  0;
223		mThumbRect.mTop = thumb_start;
224		mThumbRect.mRight = mThickness;
225		mThumbRect.mBottom = thumb_start - thumb_length;
226	}
227	else
228	{
229		// Horizontal
230		S32 thumb_start_max = thumb_bg_length + mThickness - thumb_length;
231		S32 thumb_start_min = mThickness;
232		S32 thumb_start = variable_lines ? llmin(llmax( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_min;
233	
234		mThumbRect.mLeft = thumb_start;
235		mThumbRect.mTop = mThickness;
236		mThumbRect.mRight = thumb_start + thumb_length;
237		mThumbRect.mBottom = 0;
238	}
239}
240
241BOOL LLScrollbar::handleMouseDown(S32 x, S32 y, MASK mask)
242{
243	// Check children first
244	BOOL handled_by_child = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
245	if( !handled_by_child )
246	{
247		if( mThumbRect.pointInRect(x,y) )
248		{
249			// Start dragging the thumb
250			// No handler needed for focus lost since this clas has no state that depends on it.
251			gFocusMgr.setMouseCapture( this );  
252			mDragStartX = x;
253			mDragStartY = y;
254			mOrigRect.mTop = mThumbRect.mTop;
255			mOrigRect.mBottom = mThumbRect.mBottom;
256			mOrigRect.mLeft = mThumbRect.mLeft;
257			mOrigRect.mRight = mThumbRect.mRight;
258			mLastDelta = 0;
259		}
260		else
261		{
262			if( 
263				( (LLScrollbar::VERTICAL == mOrientation) && (mThumbRect.mTop < y) ) ||
264				( (LLScrollbar::HORIZONTAL == mOrientation) && (x < mThumbRect.mLeft) )
265			)
266			{
267				// Page up
268				pageUp(0);
269			}
270			else
271			if(
272				( (LLScrollbar::VERTICAL == mOrientation) && (y < mThumbRect.mBottom) ) ||
273				( (LLScrollbar::HORIZONTAL == mOrientation) && (mThumbRect.mRight < x) )
274			)
275			{
276				// Page down
277				pageDown(0);
278			}
279		}
280	}
281
282	return TRUE;
283}
284
285
286BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
287{
288	// Note: we don't bother sending the event to the children (the arrow buttons)
289	// because they'll capture the mouse whenever they need hover events.
290	
291	BOOL handled = FALSE;
292	if( hasMouseCapture() )
293	{
294		S32 height = getRect().getHeight();
295		S32 width = getRect().getWidth();
296
297		if( VERTICAL == mOrientation )
298		{
299//			S32 old_pos = mThumbRect.mTop;
300
301			S32 delta_pixels = y - mDragStartY;
302			if( mOrigRect.mBottom + delta_pixels < mThickness )
303			{
304				delta_pixels = mThickness - mOrigRect.mBottom - 1;
305			}
306			else
307			if( mOrigRect.mTop + delta_pixels > height - mThickness )
308			{
309				delta_pixels = height - mThickness - mOrigRect.mTop + 1;
310			}
311
312			mThumbRect.mTop = mOrigRect.mTop + delta_pixels;
313			mThumbRect.mBottom = mOrigRect.mBottom + delta_pixels;
314
315			S32 thumb_length = mThumbRect.getHeight();
316			S32 thumb_track_length = height - 2 * mThickness;
317
318
319			if( delta_pixels != mLastDelta || mDocChanged)
320			{	
321				// Note: delta_pixels increases as you go up.  mDocPos increases down (line 0 is at the top of the page).
322				S32 usable_track_length = thumb_track_length - thumb_length;
323				if( 0 < usable_track_length )
324				{
325					S32 variable_lines = getDocPosMax();
326					S32 pos = mThumbRect.mTop;
327					F32 ratio = F32(pos - mThickness - thumb_length) / usable_track_length;	
328	
329					S32 new_pos = llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines );
330					// Note: we do not call updateThumbRect() here.  Instead we let the thumb and the document go slightly
331					// out of sync (less than a line's worth) to make the thumb feel responsive.
332					changeLine( new_pos - mDocPos, FALSE );
333				}
334			}
335
336			mLastDelta = delta_pixels;
337		
338		}
339		else
340		{
341			// Horizontal
342//			S32 old_pos = mThumbRect.mLeft;
343
344			S32 delta_pixels = x - mDragStartX;
345
346			if( mOrigRect.mLeft + delta_pixels < mThickness )
347			{
348				delta_pixels = mThickness - mOrigRect.mLeft - 1;
349			}
350			else
351			if( mOrigRect.mRight + delta_pixels > width - mThickness )
352			{
353				delta_pixels = width - mThickness - mOrigRect.mRight + 1;
354			}
355
356			mThumbRect.mLeft = mOrigRect.mLeft + delta_pixels;
357			mThumbRect.mRight = mOrigRect.mRight + delta_pixels;
358			
359			S32 thumb_length = mThumbRect.getWidth();
360			S32 thumb_track_length = width - 2 * mThickness;
361
362			if( delta_pixels != mLastDelta || mDocChanged)
363			{	
364				// Note: delta_pixels increases as you go up.  mDocPos increases down (line 0 is at the top of the page).
365				S32 usable_track_length = thumb_track_length - thumb_length;
366				if( 0 < usable_track_length )
367				{
368					S32 variable_lines = getDocPosMax();
369					S32 pos = mThumbRect.mLeft;
370					F32 ratio = F32(pos - mThickness) / usable_track_length;	
371	
372					S32 new_pos = llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines);
373	
374					// Note: we do not call updateThumbRect() here.  Instead we let the thumb and the document go slightly
375					// out of sync (less than a line's worth) to make the thumb feel responsive.
376					changeLine( new_pos - mDocPos, FALSE );
377				}
378			}
379
380			mLastDelta = delta_pixels;
381		}
382
383		getWindow()->setCursor(UI_CURSOR_ARROW);
384		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;		
385		handled = TRUE;
386	}
387	else
388	{
389		handled = childrenHandleHover( x, y, mask ) != NULL;
390	}
391
392	// Opaque
393	if( !handled )
394	{
395		getWindow()->setCursor(UI_CURSOR_ARROW);
396		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)"  << llendl;		
397		handled = TRUE;
398	}
399
400	mDocChanged = FALSE;
401	return handled;
402} // end handleHover
403
404
405BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks)
406{
407	BOOL handled = changeLine( clicks * mStepSize, TRUE );
408	return handled;
409}
410
411BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
412									EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string &tooltip_msg)
413{
414	// enable this to get drag and drop to control scrollbars
415	//if (!drop)
416	//{
417	//	//TODO: refactor this
418	//	S32 variable_lines = getDocPosMax();
419	//	S32 pos = (VERTICAL == mOrientation) ? y : x;
420	//	S32 thumb_length = (VERTICAL == mOrientation) ? mThumbRect.getHeight() : mThumbRect.getWidth();
421	//	S32 thumb_track_length = (VERTICAL == mOrientation) ? (getRect().getHeight() - 2 * SCROLLBAR_SIZE) : (getRect().getWidth() - 2 * SCROLLBAR_SIZE);
422	//	S32 usable_track_length = thumb_track_length - thumb_length;
423	//	F32 ratio = (VERTICAL == mOrientation) ? F32(pos - SCROLLBAR_SIZE - thumb_length) / usable_track_length
424	//		: F32(pos - SCROLLBAR_SIZE) / usable_track_length;	
425	//	S32 new_pos = (VERTICAL == mOrientation) ? llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines )
426	//		: llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines );
427	//	changeLine( new_pos - mDocPos, TRUE );
428	//}
429	//return TRUE;
430	return FALSE;
431}
432
433BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask)
434{
435	BOOL handled = FALSE;
436	if( hasMouseCapture() )
437	{
438		gFocusMgr.setMouseCapture( NULL );
439		handled = TRUE;
440	}
441	else
442	{
443		// Opaque, so don't just check children	
444		handled = LLView::handleMouseUp( x, y, mask );
445	}
446
447	return handled;
448}
449
450BOOL LLScrollbar::handleDoubleClick(S32 x, S32 y, MASK mask)
451{
452	// just treat a double click as a second click
453	return handleMouseDown(x, y, mask);
454}
455
456
457void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent)
458{
459	if (width == getRect().getWidth() && height == getRect().getHeight()) return;
460	LLView::reshape( width, height, called_from_parent );
461	LLButton* up_button = getChild<LLButton>("Line Up");
462	LLButton* down_button = getChild<LLButton>("Line Down");
463
464	if (mOrientation == VERTICAL)
465	{
466		up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness));
467		down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness));
468		up_button->setOrigin(up_button->getRect().mLeft, getRect().getHeight() - up_button->getRect().getHeight());
469	}
470	else
471	{
472		up_button->reshape(llmin(getRect().getWidth() / 2, mThickness), up_button->getRect().getHeight());
473		down_button->reshape(llmin(getRect().getWidth() / 2, mThickness), down_button->getRect().getHeight());
474		down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), down_button->getRect().mBottom);
475	}
476	updateThumbRect();
477}
478
479
480void LLScrollbar::draw()
481{
482	if (!getRect().isValid()) return;
483
484	if(mBGVisible)
485	{
486		gl_rect_2d(getLocalRect(), mBGColor.get(), TRUE);
487	}
488
489	S32 local_mouse_x;
490	S32 local_mouse_y;
491	LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
492	BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this;
493	BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y));
494	if (hovered)
495	{
496		mCurGlowStrength = lerp(mCurGlowStrength, mHoverGlowStrength, LLCriticalDamp::getInterpolant(0.05f));
497	}
498	else
499	{
500		mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLCriticalDamp::getInterpolant(0.05f));
501	}
502
503	// Draw background and thumb.
504	if (   ( mOrientation == VERTICAL&&(mThumbImageV.isNull() || mThumbImageH.isNull()) ) 
505		|| (mOrientation == HORIZONTAL&&(mTrackImageH.isNull() || mTrackImageV.isNull()) ))
506	{
507		gl_rect_2d(mOrientation == HORIZONTAL ? mThickness : 0, 
508		mOrientation == VERTICAL ? getRect().getHeight() - 2 * mThickness : getRect().getHeight(),
509		mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * mThickness : getRect().getWidth(), 
510		mOrientation == VERTICAL ? mThickness : 0, mTrackColor.get(), TRUE);
511
512		gl_rect_2d(mThumbRect, mThumbColor.get(), TRUE);
513
514	}
515	else
516	{
517		// Thumb
518		LLRect outline_rect = mThumbRect;
519		outline_rect.stretch(2);
520		// Background
521		
522		if(mOrientation == HORIZONTAL)
523		{
524			mTrackImageH->drawSolid(mThickness								//S32 x
525								   , 0										//S32 y
526								   , getRect().getWidth() - 2 * mThickness  //S32 width
527								   , getRect().getHeight()					//S32 height
528								   , mTrackColor.get());                    //const LLColor4& color
529			
530			if (gFocusMgr.getKeyboardFocus() == this)
531			{
532				mTrackImageH->draw(outline_rect, gFocusMgr.getFocusColor());
533			}
534			
535			mThumbImageH->draw(mThumbRect, mThumbColor.get());
536			if (mCurGlowStrength > 0.01f)
537			{
538				gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
539				mThumbImageH->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
540				gGL.setSceneBlendType(LLRender::BT_ALPHA);
541			}
542			
543		}
544		else if(mOrientation == VERTICAL)
545		{
546			mTrackImageV->drawSolid(  0										//S32 x
547								   , mThickness								//S32 y
548								   , getRect().getWidth()					//S32 width
549								   , getRect().getHeight() - 2 * mThickness	//S32 height
550								   , mTrackColor.get());                    //const LLColor4& color
551			if (gFocusMgr.getKeyboardFocus() == this)
552			{
553				mTrackImageV->draw(outline_rect, gFocusMgr.getFocusColor());
554			}
555			
556			mThumbImageV->draw(mThumbRect, mThumbColor.get());
557			if (mCurGlowStrength > 0.01f)
558			{
559				gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
560				mThumbImageV->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
561				gGL.setSceneBlendType(LLRender::BT_ALPHA);
562			}
563		}
564	}
565
566	// Draw children
567	LLView::draw();
568} // end draw
569
570
571bool LLScrollbar::changeLine( S32 delta, BOOL update_thumb )
572{
573	return setDocPos(mDocPos + delta, update_thumb);
574}
575
576void LLScrollbar::setValue(const LLSD& value) 
577{ 
578	setDocPos((S32) value.asInteger());
579}
580
581
582BOOL LLScrollbar::handleKeyHere(KEY key, MASK mask)
583{
584	BOOL handled = FALSE;
585
586	switch( key )
587	{
588	case KEY_HOME:
589		setDocPos( 0 );
590		handled = TRUE;
591		break;
592	
593	case KEY_END:
594		setDocPos( getDocPosMax() );
595		handled = TRUE;
596		break;
597	
598	case KEY_DOWN:
599		setDocPos( getDocPos() + mStepSize );
600		handled = TRUE;
601		break;
602	
603	case KEY_UP:
604		setDocPos( getDocPos() - mStepSize );
605		handled = TRUE;
606		break;
607
608	case KEY_PAGE_DOWN:
609		pageDown(1);
610		break;
611
612	case KEY_PAGE_UP:
613		pageUp(1);
614		break;
615	}
616
617	return handled;
618}
619
620void LLScrollbar::pageUp(S32 overlap)
621{
622	if (mDocSize > mPageSize)
623	{
624		changeLine( -(mPageSize - overlap), TRUE );
625	}
626}
627
628void LLScrollbar::pageDown(S32 overlap)
629{
630	if (mDocSize > mPageSize)
631	{
632		changeLine( mPageSize - overlap, TRUE );
633	}
634}
635
636void LLScrollbar::onLineUpBtnPressed( const LLSD& data )
637{
638	changeLine( -mStepSize, TRUE );
639}
640
641void LLScrollbar::onLineDownBtnPressed( const LLSD& data )
642{
643	changeLine( mStepSize, TRUE );
644}