aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/llscrollcontainer.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/llscrollcontainer.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llui/llscrollcontainer.cpp')
-rw-r--r--linden/indra/llui/llscrollcontainer.cpp791
1 files changed, 791 insertions, 0 deletions
diff --git a/linden/indra/llui/llscrollcontainer.cpp b/linden/indra/llui/llscrollcontainer.cpp
new file mode 100644
index 0000000..73be607
--- /dev/null
+++ b/linden/indra/llui/llscrollcontainer.cpp
@@ -0,0 +1,791 @@
1/**
2 * @file llscrollcontainer.cpp
3 * @brief LLScrollableContainerView base class
4 *
5 * Copyright (c) 2001-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//*****************************************************************************
29//
30// A view meant to encapsulate a clipped region which is
31// scrollable. It automatically takes care of pixel perfect scrolling
32// and cliipping, as well as turning the scrollbars on or off based on
33// the width and height of the view you're scrolling.
34//
35//*****************************************************************************
36
37#include "linden_common.h"
38
39#include "llgl.h"
40
41#include "llscrollcontainer.h"
42#include "llscrollbar.h"
43#include "llui.h"
44#include "llkeyboard.h"
45#include "llviewborder.h"
46#include "llfocusmgr.h"
47#include "llframetimer.h"
48#include "lluictrlfactory.h"
49#include "llfontgl.h"
50
51#include "llglheaders.h"
52
53///----------------------------------------------------------------------------
54/// Local function declarations, constants, enums, and typedefs
55///----------------------------------------------------------------------------
56
57static const S32 HORIZONTAL_MULTIPLE = 8;
58static const S32 VERTICAL_MULTIPLE = 16;
59static const F32 MIN_AUTO_SCROLL_RATE = 120.f;
60static const F32 MAX_AUTO_SCROLL_RATE = 500.f;
61static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f;
62
63///----------------------------------------------------------------------------
64/// Class LLScrollableContainerView
65///----------------------------------------------------------------------------
66
67// Default constructor
68LLScrollableContainerView::LLScrollableContainerView( const LLString& name,
69 const LLRect& rect,
70 LLView* scrolled_view,
71 BOOL is_opaque,
72 const LLColor4& bg_color ) :
73 LLUICtrl( name, rect, FALSE, NULL, NULL ),
74 mScrolledView( scrolled_view ),
75 mIsOpaque( is_opaque ),
76 mBackgroundColor( bg_color ),
77 mReserveScrollCorner( FALSE ),
78 mAutoScrolling( FALSE ),
79 mAutoScrollRate( 0.f )
80{
81 if( mScrolledView )
82 {
83 addChild( mScrolledView );
84 }
85
86 init();
87}
88
89// LLUICtrl constructor
90LLScrollableContainerView::LLScrollableContainerView( const LLString& name, const LLRect& rect,
91 LLUICtrl* scrolled_ctrl, BOOL is_opaque,
92 const LLColor4& bg_color) :
93 LLUICtrl( name, rect, FALSE, NULL, NULL ),
94 mScrolledView( scrolled_ctrl ),
95 mIsOpaque( is_opaque ),
96 mBackgroundColor( bg_color ),
97 mReserveScrollCorner( FALSE ),
98 mAutoScrolling( FALSE ),
99 mAutoScrollRate( 0.f )
100{
101 if( scrolled_ctrl )
102 {
103 addChild( scrolled_ctrl );
104 }
105
106 init();
107}
108
109void LLScrollableContainerView::init()
110{
111 LLRect border_rect( 0, mRect.getHeight(), mRect.getWidth(), 0 );
112 mBorder = new LLViewBorder( "scroll border", border_rect, LLViewBorder::BEVEL_IN );
113 addChild( mBorder );
114
115 mInnerRect.set( 0, mRect.getHeight(), mRect.getWidth(), 0 );
116 mInnerRect.stretch( -mBorder->getBorderWidth() );
117
118 LLRect vertical_scroll_rect = mInnerRect;
119 vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - SCROLLBAR_SIZE;
120 mScrollbar[VERTICAL] = new LLScrollbar( "scrollable vertical",
121 vertical_scroll_rect,
122 LLScrollbar::VERTICAL,
123 mInnerRect.getHeight(),
124 0,
125 mInnerRect.getHeight(),
126 NULL, this,
127 VERTICAL_MULTIPLE);
128 addChild( mScrollbar[VERTICAL] );
129 mScrollbar[VERTICAL]->setVisible( FALSE );
130 mScrollbar[VERTICAL]->setFollowsRight();
131 mScrollbar[VERTICAL]->setFollowsTop();
132 mScrollbar[VERTICAL]->setFollowsBottom();
133
134 LLRect horizontal_scroll_rect = mInnerRect;
135 horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + SCROLLBAR_SIZE;
136 mScrollbar[HORIZONTAL] = new LLScrollbar( "scrollable horizontal",
137 horizontal_scroll_rect,
138 LLScrollbar::HORIZONTAL,
139 mInnerRect.getWidth(),
140 0,
141 mInnerRect.getWidth(),
142 NULL, this,
143 HORIZONTAL_MULTIPLE);
144 addChild( mScrollbar[HORIZONTAL] );
145 mScrollbar[HORIZONTAL]->setVisible( FALSE );
146 mScrollbar[HORIZONTAL]->setFollowsLeft();
147 mScrollbar[HORIZONTAL]->setFollowsRight();
148
149 setTabStop(FALSE);
150}
151
152// Destroys the object
153LLScrollableContainerView::~LLScrollableContainerView( void )
154{
155 // mScrolledView and mScrollbar are child views, so the LLView
156 // destructor takes care of memory deallocation.
157 for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
158 {
159 mScrollbar[i] = NULL;
160 }
161 mScrolledView = NULL;
162}
163
164/*
165// scrollbar handlers
166void LLScrollableContainerView::horizontalChange( S32 new_pos,
167 LLScrollbar* sb,
168 void* user_data )
169{
170 LLScrollableContainerView* cont = reinterpret_cast<LLScrollableContainerView*>(user_data);
171// cont->scrollHorizontal( new_pos );
172}
173
174
175void LLScrollableContainerView::verticalChange( S32 new_pos, LLScrollbar* sb,
176 void* user_data )
177{
178 LLScrollableContainerView* cont = reinterpret_cast<LLScrollableContainerView*>(user_data);
179// cont->scrollVertical( new_pos );
180}
181*/
182
183// internal scrollbar handlers
184// virtual
185void LLScrollableContainerView::scrollHorizontal( S32 new_pos )
186{
187 //llinfos << "LLScrollableContainerView::scrollHorizontal()" << llendl;
188 if( mScrolledView )
189 {
190 LLRect doc_rect = mScrolledView->getRect();
191 S32 old_pos = -(doc_rect.mLeft - mInnerRect.mLeft);
192 mScrolledView->translate( -(new_pos - old_pos), 0 );
193 }
194}
195
196// virtual
197void LLScrollableContainerView::scrollVertical( S32 new_pos )
198{
199 // llinfos << "LLScrollableContainerView::scrollVertical() " << new_pos << llendl;
200 if( mScrolledView )
201 {
202 LLRect doc_rect = mScrolledView->getRect();
203 S32 old_pos = doc_rect.mTop - mInnerRect.mTop;
204 mScrolledView->translate( 0, new_pos - old_pos );
205 }
206}
207
208// LLView functionality
209void LLScrollableContainerView::reshape(S32 width, S32 height,
210 BOOL called_from_parent)
211{
212 LLUICtrl::reshape( width, height, called_from_parent );
213
214 mInnerRect.set( 0, mRect.getHeight(), mRect.getWidth(), 0 );
215 mInnerRect.stretch( -mBorder->getBorderWidth() );
216
217 if (mScrolledView)
218 {
219 const LLRect& scrolled_rect = mScrolledView->getRect();
220
221 S32 visible_width = 0;
222 S32 visible_height = 0;
223 BOOL show_v_scrollbar = FALSE;
224 BOOL show_h_scrollbar = FALSE;
225 calcVisibleSize( scrolled_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
226
227 mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() );
228 mScrollbar[VERTICAL]->setPageSize( visible_height );
229
230 mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() );
231 mScrollbar[HORIZONTAL]->setPageSize( visible_width );
232 }
233}
234
235BOOL LLScrollableContainerView::handleKey( KEY key, MASK mask, BOOL called_from_parent )
236{
237 if( getVisible() && mEnabled )
238 {
239 if( called_from_parent )
240 {
241 // Downward traversal
242
243 // Don't pass keys to scrollbars on downward.
244
245 // Handle 'child' view.
246 if( mScrolledView && mScrolledView->handleKey(key, mask, TRUE) )
247 {
248 return TRUE;
249 }
250 }
251 else
252 {
253 // Upward traversal
254
255 for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
256 {
257 // Note: the scrollbar _is_ actually being called from it's parent. Here
258 // we're delgating LLScrollableContainerView's upward traversal to the scrollbars
259 if( mScrollbar[i]->handleKey(key, mask, TRUE) )
260 {
261 return TRUE;
262 }
263 }
264
265 if (getParent())
266 {
267 return getParent()->handleKey( key, mask, FALSE );
268 }
269 }
270 }
271
272 return FALSE;
273}
274
275BOOL LLScrollableContainerView::handleScrollWheel( S32 x, S32 y, S32 clicks )
276{
277 if( mEnabled )
278 {
279 for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
280 {
281 // Note: tries vertical and then horizontal
282
283 // Pretend the mouse is over the scrollbar
284 if( mScrollbar[i]->handleScrollWheel( 0, 0, clicks ) )
285 {
286 return TRUE;
287 }
288 }
289 }
290
291 // Opaque
292 return TRUE;
293}
294
295BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask,
296 BOOL drop,
297 EDragAndDropType cargo_type,
298 void* cargo_data,
299 EAcceptance* accept,
300 LLString& tooltip_msg)
301{
302 // Scroll folder view if needed. Never accepts a drag or drop.
303 *accept = ACCEPT_NO;
304 BOOL handled = FALSE;
305 if( mScrollbar[HORIZONTAL]->getVisible() || mScrollbar[VERTICAL]->getVisible() )
306 {
307 const S32 AUTOSCROLL_SIZE = 10;
308 S32 auto_scroll_speed = llround(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32());
309
310 LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 );
311 if( mScrollbar[HORIZONTAL]->getVisible() )
312 {
313 inner_rect_local.mBottom += SCROLLBAR_SIZE;
314 }
315 if( mScrollbar[VERTICAL]->getVisible() )
316 {
317 inner_rect_local.mRight -= SCROLLBAR_SIZE;
318 }
319
320 if( mScrollbar[HORIZONTAL]->getVisible() )
321 {
322 LLRect left_scroll_rect = inner_rect_local;
323 left_scroll_rect.mRight = AUTOSCROLL_SIZE;
324 if( left_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() > 0) )
325 {
326 mScrollbar[HORIZONTAL]->setDocPos( mScrollbar[HORIZONTAL]->getDocPos() - auto_scroll_speed );
327 mAutoScrolling = TRUE;
328 handled = TRUE;
329 }
330
331 LLRect right_scroll_rect = inner_rect_local;
332 right_scroll_rect.mLeft = inner_rect_local.mRight - AUTOSCROLL_SIZE;
333 if( right_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() < mScrollbar[HORIZONTAL]->getDocPosMax()) )
334 {
335 mScrollbar[HORIZONTAL]->setDocPos( mScrollbar[HORIZONTAL]->getDocPos() + auto_scroll_speed );
336 mAutoScrolling = TRUE;
337 handled = TRUE;
338 }
339 }
340 if( mScrollbar[VERTICAL]->getVisible() )
341 {
342 LLRect bottom_scroll_rect = inner_rect_local;
343 bottom_scroll_rect.mTop = AUTOSCROLL_SIZE + bottom_scroll_rect.mBottom;
344 if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() < mScrollbar[VERTICAL]->getDocPosMax()) )
345 {
346 mScrollbar[VERTICAL]->setDocPos( mScrollbar[VERTICAL]->getDocPos() + auto_scroll_speed );
347 mAutoScrolling = TRUE;
348 handled = TRUE;
349 }
350
351 LLRect top_scroll_rect = inner_rect_local;
352 top_scroll_rect.mBottom = inner_rect_local.mTop - AUTOSCROLL_SIZE;
353 if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() > 0) )
354 {
355 mScrollbar[VERTICAL]->setDocPos( mScrollbar[VERTICAL]->getDocPos() - auto_scroll_speed );
356 mAutoScrolling = TRUE;
357 handled = TRUE;
358 }
359 }
360 }
361
362 if( !handled )
363 {
364 handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type,
365 cargo_data, accept, tooltip_msg) != NULL;
366 }
367
368 return TRUE;
369}
370
371
372BOOL LLScrollableContainerView::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect)
373{
374 if( getVisible() && pointInView(x,y) )
375 {
376 S32 local_x, local_y;
377 for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
378 {
379 local_x = x - mScrollbar[i]->getRect().mLeft;
380 local_y = y - mScrollbar[i]->getRect().mBottom;
381 if( mScrollbar[i]->handleToolTip(local_x, local_y, msg, sticky_rect) )
382 {
383 return TRUE;
384 }
385 }
386 // Handle 'child' view.
387 if( mScrolledView )
388 {
389 local_x = x - mScrolledView->getRect().mLeft;
390 local_y = y - mScrolledView->getRect().mBottom;
391 if( mScrolledView->handleToolTip(local_x, local_y, msg, sticky_rect) )
392 {
393 return TRUE;
394 }
395 }
396
397 // Opaque
398 return TRUE;
399 }
400 return FALSE;
401}
402
403void LLScrollableContainerView::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar )
404{
405 const LLRect& rect = mScrolledView->getRect();
406 calcVisibleSize(rect, visible_width, visible_height, show_h_scrollbar, show_v_scrollbar);
407}
408
409void LLScrollableContainerView::calcVisibleSize( const LLRect& doc_rect, S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar )
410{
411 S32 doc_width = doc_rect.getWidth();
412 S32 doc_height = doc_rect.getHeight();
413
414 *visible_width = mRect.getWidth() - 2 * mBorder->getBorderWidth();
415 *visible_height = mRect.getHeight() - 2 * mBorder->getBorderWidth();
416
417 *show_v_scrollbar = FALSE;
418 if( *visible_height < doc_height )
419 {
420 *show_v_scrollbar = TRUE;
421 *visible_width -= SCROLLBAR_SIZE;
422 }
423
424 *show_h_scrollbar = FALSE;
425 if( *visible_width < doc_width )
426 {
427 *show_h_scrollbar = TRUE;
428 *visible_height -= SCROLLBAR_SIZE;
429
430 // Must retest now that visible_height has changed
431 if( !*show_v_scrollbar && (*visible_height < doc_height) )
432 {
433 *show_v_scrollbar = TRUE;
434 *visible_width -= SCROLLBAR_SIZE;
435 }
436 }
437}
438
439void LLScrollableContainerView::draw()
440{
441 if (mAutoScrolling)
442 {
443 // add acceleration to autoscroll
444 mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), MAX_AUTO_SCROLL_RATE);
445 }
446 else
447 {
448 // reset to minimum
449 mAutoScrollRate = MIN_AUTO_SCROLL_RATE;
450 }
451 // clear this flag to be set on next call to handleDragAndDrop
452 mAutoScrolling = FALSE;
453
454 if( getVisible() )
455 {
456 // auto-focus when scrollbar active
457 // this allows us to capture user intent (i.e. stop automatically scrolling the view/etc)
458 if (!gFocusMgr.childHasKeyboardFocus(this) &&
459 (gFocusMgr.getMouseCapture() == mScrollbar[VERTICAL] || gFocusMgr.getMouseCapture() == mScrollbar[HORIZONTAL]))
460 {
461 focusFirstItem();
462 }
463
464 // Draw background
465 if( mIsOpaque )
466 {
467 LLGLSNoTexture no_texture;
468 glColor4fv( mBackgroundColor.mV );
469 gl_rect_2d( mInnerRect );
470 }
471
472 // Draw mScrolledViews and update scroll bars.
473 // get a scissor region ready, and draw the scrolling view. The
474 // scissor region ensures that we don't draw outside of the bounds
475 // of the rectangle.
476 if( mScrolledView )
477 {
478 updateScroll();
479
480 // Draw the scrolled area.
481 {
482 S32 visible_width = 0;
483 S32 visible_height = 0;
484 BOOL show_v_scrollbar = FALSE;
485 BOOL show_h_scrollbar = FALSE;
486 calcVisibleSize( mScrolledView->getRect(), &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
487
488 LLGLEnable scissor_test(GL_SCISSOR_TEST);
489 LLUI::setScissorRegionLocal(LLRect(mInnerRect.mLeft,
490 mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) + visible_height,
491 visible_width,
492 mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0)
493 ));
494 drawChild(mScrolledView);
495 }
496 }
497
498 // Highlight border if a child of this container has keyboard focus
499 if( mBorder->getVisible() )
500 {
501 mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) );
502 }
503
504 // Draw all children except mScrolledView
505 // Note: scrollbars have been adjusted by above drawing code
506 for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin();
507 child_iter != getChildList()->rend(); ++child_iter)
508 {
509 LLView *viewp = *child_iter;
510 if( sDebugRects )
511 {
512 sDepth++;
513 }
514 if( (viewp != mScrolledView) && viewp->getVisible() )
515 {
516 drawChild(viewp);
517 }
518 if( sDebugRects )
519 {
520 sDepth--;
521 }
522 }
523
524 if (sDebugRects)
525 {
526 drawDebugRect();
527 }
528 }
529}
530
531void LLScrollableContainerView::updateScroll()
532{
533 LLRect doc_rect = mScrolledView->getRect();
534 S32 doc_width = doc_rect.getWidth();
535 S32 doc_height = doc_rect.getHeight();
536 S32 visible_width = 0;
537 S32 visible_height = 0;
538 BOOL show_v_scrollbar = FALSE;
539 BOOL show_h_scrollbar = FALSE;
540 calcVisibleSize( doc_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
541
542 S32 border_width = mBorder->getBorderWidth();
543 if( show_v_scrollbar )
544 {
545 if( doc_rect.mTop < mRect.getHeight() - border_width )
546 {
547 mScrolledView->translate( 0, mRect.getHeight() - border_width - doc_rect.mTop );
548 }
549
550 scrollVertical( mScrollbar[VERTICAL]->getDocPos() );
551 mScrollbar[VERTICAL]->setVisible( TRUE );
552
553 S32 v_scrollbar_height = visible_height;
554 if( !show_h_scrollbar && mReserveScrollCorner )
555 {
556 v_scrollbar_height -= SCROLLBAR_SIZE;
557 }
558 mScrollbar[VERTICAL]->reshape( SCROLLBAR_SIZE, v_scrollbar_height, TRUE );
559
560 // Make room for the horizontal scrollbar (or not)
561 S32 v_scrollbar_offset = 0;
562 if( show_h_scrollbar || mReserveScrollCorner )
563 {
564 v_scrollbar_offset = SCROLLBAR_SIZE;
565 }
566 LLRect r = mScrollbar[VERTICAL]->getRect();
567 r.translate( 0, mInnerRect.mBottom - r.mBottom + v_scrollbar_offset );
568 mScrollbar[VERTICAL]->setRect( r );
569 }
570 else
571 {
572 mScrolledView->translate( 0, mRect.getHeight() - border_width - doc_rect.mTop );
573
574 mScrollbar[VERTICAL]->setVisible( FALSE );
575 mScrollbar[VERTICAL]->setDocPos( 0 );
576 }
577
578 if( show_h_scrollbar )
579 {
580 if( doc_rect.mLeft > border_width )
581 {
582 mScrolledView->translate( border_width - doc_rect.mLeft, 0 );
583 mScrollbar[HORIZONTAL]->setDocPos( 0 );
584 }
585 else
586 {
587 scrollHorizontal( mScrollbar[HORIZONTAL]->getDocPos() );
588 }
589
590 mScrollbar[HORIZONTAL]->setVisible( TRUE );
591 S32 h_scrollbar_width = visible_width;
592 if( !show_v_scrollbar && mReserveScrollCorner )
593 {
594 h_scrollbar_width -= SCROLLBAR_SIZE;
595 }
596 mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, SCROLLBAR_SIZE, TRUE );
597 }
598 else
599 {
600 mScrolledView->translate( border_width - doc_rect.mLeft, 0 );
601
602 mScrollbar[HORIZONTAL]->setVisible( FALSE );
603 mScrollbar[HORIZONTAL]->setDocPos( 0 );
604 }
605
606 mScrollbar[HORIZONTAL]->setDocSize( doc_width );
607 mScrollbar[HORIZONTAL]->setPageSize( visible_width );
608
609 mScrollbar[VERTICAL]->setDocSize( doc_height );
610 mScrollbar[VERTICAL]->setPageSize( visible_height );
611}
612
613void LLScrollableContainerView::setBorderVisible(BOOL b)
614{
615 mBorder->setVisible( b );
616}
617
618// Scroll so that as much of rect as possible is showing (where rect is defined in the space of scroller view, not scrolled)
619void LLScrollableContainerView::scrollToShowRect(const LLRect& rect, const LLCoordGL& desired_offset)
620{
621 if (!mScrolledView)
622 {
623 llwarns << "LLScrollableContainerView::scrollToShowRect with no view!" << llendl;
624 return;
625 }
626
627 S32 visible_width = 0;
628 S32 visible_height = 0;
629 BOOL show_v_scrollbar = FALSE;
630 BOOL show_h_scrollbar = FALSE;
631 const LLRect& scrolled_rect = mScrolledView->getRect();
632 calcVisibleSize( scrolled_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
633
634 // can't be so far left that right side of rect goes off screen, or so far right that left side does
635 S32 horiz_offset = llclamp(desired_offset.mX, llmin(0, -visible_width + rect.getWidth()), 0);
636 // can't be so high that bottom of rect goes off screen, or so low that top does
637 S32 vert_offset = llclamp(desired_offset.mY, 0, llmax(0, visible_height - rect.getHeight()));
638
639 // Vertical
640 // 1. First make sure the top is visible
641 // 2. Then, if possible without hiding the top, make the bottom visible.
642 S32 vert_pos = mScrollbar[VERTICAL]->getDocPos();
643
644 // find scrollbar position to get top of rect on screen (scrolling up)
645 S32 top_offset = scrolled_rect.mTop - rect.mTop - vert_offset;
646 // find scrollbar position to get bottom of rect on screen (scrolling down)
647 S32 bottom_offset = vert_offset == 0 ? scrolled_rect.mTop - rect.mBottom - visible_height : top_offset;
648 // scroll up far enough to see top or scroll down just enough if item is bigger than visual area
649 if( vert_pos >= top_offset || visible_height < rect.getHeight())
650 {
651 vert_pos = top_offset;
652 }
653 // else scroll down far enough to see bottom
654 else
655 if( vert_pos <= bottom_offset )
656 {
657 vert_pos = bottom_offset;
658 }
659
660 mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() );
661 mScrollbar[VERTICAL]->setPageSize( visible_height );
662 mScrollbar[VERTICAL]->setDocPos( vert_pos );
663
664 // Horizontal
665 // 1. First make sure left side is visible
666 // 2. Then, if possible without hiding the left side, make the right side visible.
667 S32 horiz_pos = mScrollbar[HORIZONTAL]->getDocPos();
668 S32 left_offset = rect.mLeft - scrolled_rect.mLeft + horiz_offset;
669 S32 right_offset = horiz_offset == 0 ? rect.mRight - scrolled_rect.mLeft - visible_width : left_offset;
670
671 if( horiz_pos >= left_offset || visible_width < rect.getWidth() )
672 {
673 horiz_pos = left_offset;
674 }
675 else if( horiz_pos <= right_offset )
676 {
677 horiz_pos = right_offset;
678 }
679
680 mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() );
681 mScrollbar[HORIZONTAL]->setPageSize( visible_width );
682 mScrollbar[HORIZONTAL]->setDocPos( horiz_pos );
683
684 // propagate scroll to document
685 updateScroll();
686}
687
688void LLScrollableContainerView::pageUp(S32 overlap)
689{
690 mScrollbar[VERTICAL]->pageUp(overlap);
691}
692
693void LLScrollableContainerView::pageDown(S32 overlap)
694{
695 mScrollbar[VERTICAL]->pageDown(overlap);
696}
697
698void LLScrollableContainerView::goToTop()
699{
700 mScrollbar[VERTICAL]->setDocPos(0);
701}
702
703void LLScrollableContainerView::goToBottom()
704{
705 mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocSize());
706}
707
708S32 LLScrollableContainerView::getBorderWidth()
709{
710 if (mBorder)
711 {
712 return mBorder->getBorderWidth();
713 }
714
715 return 0;
716}
717
718// virtual
719LLXMLNodePtr LLScrollableContainerView::getXML(bool save_children) const
720{
721 LLXMLNodePtr node = LLView::getXML();
722
723 // Attributes
724
725 node->createChild("opaque", TRUE)->setBoolValue(mIsOpaque);
726
727 if (mIsOpaque)
728 {
729 node->createChild("color", TRUE)->setFloatValue(4, mBackgroundColor.mV);
730 }
731
732 // Contents
733
734 LLXMLNodePtr child_node = mScrolledView->getXML();
735
736 node->addChild(child_node);
737
738 return node;
739}
740
741LLView* LLScrollableContainerView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
742{
743 LLString name("scroll_container");
744 node->getAttributeString("name", name);
745
746 LLRect rect;
747 createRect(node, rect, parent, LLRect());
748
749 BOOL opaque = FALSE;
750 node->getAttributeBOOL("opaque", opaque);
751
752 LLColor4 color(0,0,0,0);
753 LLUICtrlFactory::getAttributeColor(node,"color", color);
754
755 // Create the scroll view
756 LLScrollableContainerView *ret = new LLScrollableContainerView(name, rect, (LLPanel*)NULL, opaque, color);
757
758 LLPanel* panelp = NULL;
759
760 // Find a child panel to add
761 LLXMLNodePtr child;
762 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
763 {
764 LLView *control = factory->createCtrlWidget(panelp, child);
765 if (control && control->isPanel())
766 {
767 if (panelp)
768 {
769 llinfos << "Warning! Attempting to put multiple panels into a scrollable container view!" << llendl;
770 delete control;
771 }
772 else
773 {
774 panelp = (LLPanel*)control;
775 }
776 }
777 }
778
779 if (panelp == NULL)
780 {
781 panelp = new LLPanel("dummy", LLRect::null, FALSE);
782 }
783
784 ret->mScrolledView = panelp;
785
786 return ret;
787}
788
789///----------------------------------------------------------------------------
790/// Local function definitions
791///----------------------------------------------------------------------------