llscrollcontainer.cpp

Go to the documentation of this file.
00001 
00033 #include "linden_common.h"
00034 
00035 #include "llgl.h"
00036 #include "llglimmediate.h"
00037 
00038 #include "llscrollcontainer.h"
00039 #include "llscrollbar.h"
00040 #include "llui.h"
00041 #include "llkeyboard.h"
00042 #include "llviewborder.h"
00043 #include "llfocusmgr.h"
00044 #include "llframetimer.h"
00045 #include "lluictrlfactory.h"
00046 #include "llfontgl.h"
00047 
00048 #include "llglheaders.h"
00049 
00053 
00054 static const S32 HORIZONTAL_MULTIPLE = 8;
00055 static const S32 VERTICAL_MULTIPLE = 16;
00056 static const F32 MIN_AUTO_SCROLL_RATE = 120.f;
00057 static const F32 MAX_AUTO_SCROLL_RATE = 500.f;
00058 static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f;
00059 
00063 
00064 static LLRegisterWidget<LLScrollableContainerView> r("scroll_container");
00065 
00066 // Default constructor
00067 LLScrollableContainerView::LLScrollableContainerView( const LLString& name,
00068                                                                                                           const LLRect& rect,
00069                                                                                                           LLView* scrolled_view,
00070                                                                                                           BOOL is_opaque,
00071                                                                                                           const LLColor4& bg_color ) :
00072         LLUICtrl( name, rect, FALSE, NULL, NULL ),
00073         mScrolledView( scrolled_view ),
00074         mIsOpaque( is_opaque ),
00075         mBackgroundColor( bg_color ),
00076         mReserveScrollCorner( FALSE ),
00077         mAutoScrolling( FALSE ),
00078         mAutoScrollRate( 0.f )
00079 {
00080         if( mScrolledView )
00081         {
00082                 addChild( mScrolledView );
00083         }
00084 
00085         init();
00086 }
00087 
00088 // LLUICtrl constructor
00089 LLScrollableContainerView::LLScrollableContainerView( const LLString& name, const LLRect& rect,
00090                                                            LLUICtrl* scrolled_ctrl, BOOL is_opaque,
00091                                                            const LLColor4& bg_color) :
00092         LLUICtrl( name, rect, FALSE, NULL, NULL ),
00093         mScrolledView( scrolled_ctrl ),
00094         mIsOpaque( is_opaque ),
00095         mBackgroundColor( bg_color ),
00096         mReserveScrollCorner( FALSE ),
00097         mAutoScrolling( FALSE ),
00098         mAutoScrollRate( 0.f )
00099 {
00100         if( scrolled_ctrl )
00101         {
00102                 addChild( scrolled_ctrl );
00103         }
00104 
00105         init();
00106 }
00107 
00108 void LLScrollableContainerView::init()
00109 {
00110         LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 );
00111         mBorder = new LLViewBorder( "scroll border", border_rect, LLViewBorder::BEVEL_IN );
00112         addChild( mBorder );
00113 
00114         mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 );
00115         mInnerRect.stretch( -mBorder->getBorderWidth()  );
00116 
00117         LLRect vertical_scroll_rect = mInnerRect;
00118         vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - SCROLLBAR_SIZE;
00119         mScrollbar[VERTICAL] = new LLScrollbar( "scrollable vertical",
00120                                                                                         vertical_scroll_rect,
00121                                                                                         LLScrollbar::VERTICAL,
00122                                                                                         mInnerRect.getHeight(), 
00123                                                                                         0,
00124                                                                                         mInnerRect.getHeight(),
00125                                                                                         NULL, this,
00126                                                                                         VERTICAL_MULTIPLE);
00127         addChild( mScrollbar[VERTICAL] );
00128         mScrollbar[VERTICAL]->setVisible( FALSE );
00129         mScrollbar[VERTICAL]->setFollowsRight();
00130         mScrollbar[VERTICAL]->setFollowsTop();
00131         mScrollbar[VERTICAL]->setFollowsBottom();
00132         
00133         LLRect horizontal_scroll_rect = mInnerRect;
00134         horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + SCROLLBAR_SIZE;
00135         mScrollbar[HORIZONTAL] = new LLScrollbar( "scrollable horizontal",
00136                                                                                           horizontal_scroll_rect,
00137                                                                                           LLScrollbar::HORIZONTAL,
00138                                                                                           mInnerRect.getWidth(),
00139                                                                                           0,
00140                                                                                           mInnerRect.getWidth(),
00141                                                                                           NULL, this,
00142                                                                                           HORIZONTAL_MULTIPLE);
00143         addChild( mScrollbar[HORIZONTAL] );
00144         mScrollbar[HORIZONTAL]->setVisible( FALSE );
00145         mScrollbar[HORIZONTAL]->setFollowsLeft();
00146         mScrollbar[HORIZONTAL]->setFollowsRight();
00147 
00148         setTabStop(FALSE);
00149 }
00150 
00151 // Destroys the object
00152 LLScrollableContainerView::~LLScrollableContainerView( void )
00153 {
00154         // mScrolledView and mScrollbar are child views, so the LLView
00155         // destructor takes care of memory deallocation.
00156         for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
00157         {
00158                 mScrollbar[i] = NULL;
00159         }
00160         mScrolledView = NULL;
00161 }
00162 
00163 // internal scrollbar handlers
00164 // virtual
00165 void LLScrollableContainerView::scrollHorizontal( S32 new_pos )
00166 {
00167         //llinfos << "LLScrollableContainerView::scrollHorizontal()" << llendl;
00168         if( mScrolledView )
00169         {
00170                 LLRect doc_rect = mScrolledView->getRect();
00171                 S32 old_pos = -(doc_rect.mLeft - mInnerRect.mLeft);
00172                 mScrolledView->translate( -(new_pos - old_pos), 0 );
00173         }
00174 }
00175 
00176 // virtual
00177 void LLScrollableContainerView::scrollVertical( S32 new_pos )
00178 {
00179         // llinfos << "LLScrollableContainerView::scrollVertical() " << new_pos << llendl;
00180         if( mScrolledView )
00181         {
00182                 LLRect doc_rect = mScrolledView->getRect();
00183                 S32 old_pos = doc_rect.mTop - mInnerRect.mTop;
00184                 mScrolledView->translate( 0, new_pos - old_pos );
00185         }
00186 }
00187 
00188 // LLView functionality
00189 void LLScrollableContainerView::reshape(S32 width, S32 height,
00190                                                                                 BOOL called_from_parent)
00191 {
00192         LLUICtrl::reshape( width, height, called_from_parent );
00193 
00194         mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 );
00195         mInnerRect.stretch( -mBorder->getBorderWidth() );
00196 
00197         if (mScrolledView)
00198         {
00199                 const LLRect& scrolled_rect = mScrolledView->getRect();
00200 
00201                 S32 visible_width = 0;
00202                 S32 visible_height = 0;
00203                 BOOL show_v_scrollbar = FALSE;
00204                 BOOL show_h_scrollbar = FALSE;
00205                 calcVisibleSize( scrolled_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
00206 
00207                 mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() );
00208                 mScrollbar[VERTICAL]->setPageSize( visible_height );
00209 
00210                 mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() );
00211                 mScrollbar[HORIZONTAL]->setPageSize( visible_width );
00212         }
00213 }
00214 
00215 BOOL LLScrollableContainerView::handleKeyHere(KEY key, MASK mask)
00216 {
00217         for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
00218         {
00219                 if( mScrollbar[i]->handleKeyHere(key, mask) )
00220                 {
00221                         return TRUE;
00222                 }
00223         }       
00224 
00225         return FALSE;
00226 }
00227 
00228 BOOL LLScrollableContainerView::handleScrollWheel( S32 x, S32 y, S32 clicks )
00229 {
00230         for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
00231         {
00232                 // Note: tries vertical and then horizontal
00233 
00234                 // Pretend the mouse is over the scrollbar
00235                 if( mScrollbar[i]->handleScrollWheel( 0, 0, clicks ) )
00236                 {
00237                         return TRUE;
00238                 }
00239         }
00240 
00241         // Eat scroll wheel event (to avoid scrolling nested containers?)
00242         return TRUE;
00243 }
00244 
00245 BOOL LLScrollableContainerView::needsToScroll(S32 x, S32 y, LLScrollableContainerView::SCROLL_ORIENTATION axis) const
00246 {
00247         if(mScrollbar[axis]->getVisible())
00248         {
00249                 LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 );
00250                 const S32 AUTOSCROLL_SIZE = 10;
00251                 if(mScrollbar[axis]->getVisible())
00252                 {
00253                         inner_rect_local.mRight -= SCROLLBAR_SIZE;
00254                         inner_rect_local.mTop += AUTOSCROLL_SIZE;
00255                         inner_rect_local.mBottom = inner_rect_local.mTop - AUTOSCROLL_SIZE;
00256                 }
00257                 if( inner_rect_local.pointInRect( x, y ) && (mScrollbar[axis]->getDocPos() > 0) )
00258                 {
00259                         return TRUE;
00260                 }
00261 
00262         }
00263         return FALSE;
00264 }
00265 
00266 BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask,
00267                                                                                                   BOOL drop,
00268                                                                                                   EDragAndDropType cargo_type,
00269                                                                                                   void* cargo_data,
00270                                                                                                   EAcceptance* accept,
00271                                                                                                   LLString& tooltip_msg)
00272 {
00273         // Scroll folder view if needed.  Never accepts a drag or drop.
00274         *accept = ACCEPT_NO;
00275         BOOL handled = FALSE;
00276         if( mScrollbar[HORIZONTAL]->getVisible() || mScrollbar[VERTICAL]->getVisible() )
00277         {
00278                 const S32 AUTOSCROLL_SIZE = 10;
00279                 S32 auto_scroll_speed = llround(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32());
00280                 
00281                 LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 );
00282                 if(     mScrollbar[HORIZONTAL]->getVisible() )
00283                 {
00284                         inner_rect_local.mBottom += SCROLLBAR_SIZE;
00285                 }
00286                 if(     mScrollbar[VERTICAL]->getVisible() )
00287                 {
00288                         inner_rect_local.mRight -= SCROLLBAR_SIZE;
00289                 }
00290 
00291                 if(     mScrollbar[HORIZONTAL]->getVisible() )
00292                 {
00293                         LLRect left_scroll_rect = inner_rect_local;
00294                         left_scroll_rect.mRight = AUTOSCROLL_SIZE;
00295                         if( left_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() > 0) )
00296                         {
00297                                 mScrollbar[HORIZONTAL]->setDocPos( mScrollbar[HORIZONTAL]->getDocPos() - auto_scroll_speed );
00298                                 mAutoScrolling = TRUE;
00299                                 handled = TRUE;
00300                         }
00301 
00302                         LLRect right_scroll_rect = inner_rect_local;
00303                         right_scroll_rect.mLeft = inner_rect_local.mRight - AUTOSCROLL_SIZE;
00304                         if( right_scroll_rect.pointInRect( x, y ) && (mScrollbar[HORIZONTAL]->getDocPos() < mScrollbar[HORIZONTAL]->getDocPosMax()) )
00305                         {
00306                                 mScrollbar[HORIZONTAL]->setDocPos( mScrollbar[HORIZONTAL]->getDocPos() + auto_scroll_speed );
00307                                 mAutoScrolling = TRUE;
00308                                 handled = TRUE;
00309                         }
00310                 }
00311                 if(     mScrollbar[VERTICAL]->getVisible() )
00312                 {
00313                         LLRect bottom_scroll_rect = inner_rect_local;
00314                         bottom_scroll_rect.mTop = AUTOSCROLL_SIZE + bottom_scroll_rect.mBottom;
00315                         if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() < mScrollbar[VERTICAL]->getDocPosMax()) )
00316                         {
00317                                 mScrollbar[VERTICAL]->setDocPos( mScrollbar[VERTICAL]->getDocPos() + auto_scroll_speed );
00318                                 mAutoScrolling = TRUE;
00319                                 handled = TRUE;
00320                         }
00321 
00322                         LLRect top_scroll_rect = inner_rect_local;
00323                         top_scroll_rect.mBottom = inner_rect_local.mTop - AUTOSCROLL_SIZE;
00324                         if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar[VERTICAL]->getDocPos() > 0) )
00325                         {
00326                                 mScrollbar[VERTICAL]->setDocPos( mScrollbar[VERTICAL]->getDocPos() - auto_scroll_speed );
00327                                 mAutoScrolling = TRUE;
00328                                 handled = TRUE;
00329                         }
00330                 }
00331         }
00332 
00333         if( !handled )
00334         {
00335                 handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type,
00336                                                                                         cargo_data, accept, tooltip_msg) != NULL;
00337         }
00338 
00339         return TRUE;
00340 }
00341 
00342 
00343 BOOL LLScrollableContainerView::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect)
00344 {
00345         S32 local_x, local_y;
00346         for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
00347         {
00348                 local_x = x - mScrollbar[i]->getRect().mLeft;
00349                 local_y = y - mScrollbar[i]->getRect().mBottom;
00350                 if( mScrollbar[i]->handleToolTip(local_x, local_y, msg, sticky_rect) )
00351                 {
00352                         return TRUE;
00353                 }
00354         }
00355         // Handle 'child' view.
00356         if( mScrolledView )
00357         {
00358                 local_x = x - mScrolledView->getRect().mLeft;
00359                 local_y = y - mScrolledView->getRect().mBottom;
00360                 if( mScrolledView->handleToolTip(local_x, local_y, msg, sticky_rect) )
00361                 {
00362                         return TRUE;
00363                 }
00364         }
00365 
00366         // Opaque
00367         return TRUE;
00368 }
00369 
00370 void LLScrollableContainerView::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const
00371 {
00372         const LLRect& rect = mScrolledView->getRect();
00373         calcVisibleSize(rect, visible_width, visible_height, show_h_scrollbar, show_v_scrollbar);
00374 }
00375 
00376 void LLScrollableContainerView::calcVisibleSize( const LLRect& doc_rect, S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const
00377 {
00378         S32 doc_width = doc_rect.getWidth();
00379         S32 doc_height = doc_rect.getHeight();
00380 
00381         *visible_width = getRect().getWidth() - 2 * mBorder->getBorderWidth();
00382         *visible_height = getRect().getHeight() - 2 * mBorder->getBorderWidth();
00383         
00384         *show_v_scrollbar = FALSE;
00385         if( *visible_height < doc_height )
00386         {
00387                 *show_v_scrollbar = TRUE;
00388                 *visible_width -= SCROLLBAR_SIZE;
00389         }
00390 
00391         *show_h_scrollbar = FALSE;
00392         if( *visible_width < doc_width )
00393         {
00394                 *show_h_scrollbar = TRUE;
00395                 *visible_height -= SCROLLBAR_SIZE;
00396 
00397                 // Must retest now that visible_height has changed
00398                 if( !*show_v_scrollbar && (*visible_height < doc_height) )
00399                 {
00400                         *show_v_scrollbar = TRUE;
00401                         *visible_width -= SCROLLBAR_SIZE;
00402                 }
00403         }
00404 }
00405 
00406 void LLScrollableContainerView::draw()
00407 {
00408         if (mAutoScrolling)
00409         {
00410                 // add acceleration to autoscroll
00411                 mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), MAX_AUTO_SCROLL_RATE);
00412         }
00413         else
00414         {
00415                 // reset to minimum
00416                 mAutoScrollRate = MIN_AUTO_SCROLL_RATE;
00417         }
00418         // clear this flag to be set on next call to handleDragAndDrop
00419         mAutoScrolling = FALSE;
00420 
00421         // auto-focus when scrollbar active
00422         // this allows us to capture user intent (i.e. stop automatically scrolling the view/etc)
00423         if (!gFocusMgr.childHasKeyboardFocus(this) && 
00424                 (mScrollbar[VERTICAL]->hasMouseCapture() || mScrollbar[HORIZONTAL]->hasMouseCapture()))
00425         {
00426                 focusFirstItem();
00427         }
00428 
00429         // Draw background
00430         if( mIsOpaque )
00431         {
00432                 LLGLSNoTexture no_texture;
00433                 gGL.color4fv( mBackgroundColor.mV );
00434                 gl_rect_2d( mInnerRect );
00435         }
00436         
00437         // Draw mScrolledViews and update scroll bars.
00438         // get a scissor region ready, and draw the scrolling view. The
00439         // scissor region ensures that we don't draw outside of the bounds
00440         // of the rectangle.
00441         if( mScrolledView )
00442         {
00443                 updateScroll();
00444 
00445                 // Draw the scrolled area.
00446                 {
00447                         S32 visible_width = 0;
00448                         S32 visible_height = 0;
00449                         BOOL show_v_scrollbar = FALSE;
00450                         BOOL show_h_scrollbar = FALSE;
00451                         calcVisibleSize( mScrolledView->getRect(), &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
00452 
00453                         LLLocalClipRect clip(LLRect(mInnerRect.mLeft, 
00454                                         mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) + visible_height,
00455                                         visible_width,
00456                                         mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0)
00457                                         ));
00458                         drawChild(mScrolledView);
00459                 }
00460         }
00461 
00462         // Highlight border if a child of this container has keyboard focus
00463         if( mBorder->getVisible() )
00464         {
00465                 mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) );
00466         }
00467 
00468         // Draw all children except mScrolledView
00469         // Note: scrollbars have been adjusted by above drawing code
00470         for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin();
00471                  child_iter != getChildList()->rend(); ++child_iter)
00472         {
00473                 LLView *viewp = *child_iter;
00474                 if( sDebugRects )
00475                 {
00476                         sDepth++;
00477                 }
00478                 if( (viewp != mScrolledView) && viewp->getVisible() )
00479                 {
00480                         drawChild(viewp);
00481                 }
00482                 if( sDebugRects )
00483                 {
00484                         sDepth--;
00485                 }
00486         }
00487 
00488         if (sDebugRects)
00489         {
00490                 drawDebugRect();
00491         }
00492 
00493 } // end draw
00494 
00495 void LLScrollableContainerView::updateScroll()
00496 {
00497         LLRect doc_rect = mScrolledView->getRect();
00498         S32 doc_width = doc_rect.getWidth();
00499         S32 doc_height = doc_rect.getHeight();
00500         S32 visible_width = 0;
00501         S32 visible_height = 0;
00502         BOOL show_v_scrollbar = FALSE;
00503         BOOL show_h_scrollbar = FALSE;
00504         calcVisibleSize( doc_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
00505 
00506         S32 border_width = mBorder->getBorderWidth();
00507         if( show_v_scrollbar )
00508         {
00509                 if( doc_rect.mTop < getRect().getHeight() - border_width )
00510                 {
00511                         mScrolledView->translate( 0, getRect().getHeight() - border_width - doc_rect.mTop );
00512                 }
00513 
00514                 scrollVertical( mScrollbar[VERTICAL]->getDocPos() );
00515                 mScrollbar[VERTICAL]->setVisible( TRUE );
00516 
00517                 S32 v_scrollbar_height = visible_height;
00518                 if( !show_h_scrollbar && mReserveScrollCorner )
00519                 {
00520                         v_scrollbar_height -= SCROLLBAR_SIZE;
00521                 }
00522                 mScrollbar[VERTICAL]->reshape( SCROLLBAR_SIZE, v_scrollbar_height, TRUE );
00523 
00524                 // Make room for the horizontal scrollbar (or not)
00525                 S32 v_scrollbar_offset = 0;
00526                 if( show_h_scrollbar || mReserveScrollCorner )
00527                 {
00528                         v_scrollbar_offset = SCROLLBAR_SIZE;
00529                 }
00530                 LLRect r = mScrollbar[VERTICAL]->getRect();
00531                 r.translate( 0, mInnerRect.mBottom - r.mBottom + v_scrollbar_offset );
00532                 mScrollbar[VERTICAL]->setRect( r );
00533         }
00534         else
00535         {
00536                 mScrolledView->translate( 0, getRect().getHeight() - border_width - doc_rect.mTop );
00537 
00538                 mScrollbar[VERTICAL]->setVisible( FALSE );
00539                 mScrollbar[VERTICAL]->setDocPos( 0 );
00540         }
00541                 
00542         if( show_h_scrollbar )
00543         {
00544                 if( doc_rect.mLeft > border_width )
00545                 {
00546                         mScrolledView->translate( border_width - doc_rect.mLeft, 0 );
00547                         mScrollbar[HORIZONTAL]->setDocPos( 0 );
00548                 }
00549                 else
00550                 {
00551                         scrollHorizontal( mScrollbar[HORIZONTAL]->getDocPos() );
00552                 }
00553         
00554                 mScrollbar[HORIZONTAL]->setVisible( TRUE );
00555                 S32 h_scrollbar_width = visible_width;
00556                 if( !show_v_scrollbar && mReserveScrollCorner )
00557                 {
00558                         h_scrollbar_width -= SCROLLBAR_SIZE;
00559                 }
00560                 mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, SCROLLBAR_SIZE, TRUE );
00561         }
00562         else
00563         {
00564                 mScrolledView->translate( border_width - doc_rect.mLeft, 0 );
00565                 
00566                 mScrollbar[HORIZONTAL]->setVisible( FALSE );
00567                 mScrollbar[HORIZONTAL]->setDocPos( 0 );
00568         }
00569 
00570         mScrollbar[HORIZONTAL]->setDocSize( doc_width );
00571         mScrollbar[HORIZONTAL]->setPageSize( visible_width );
00572 
00573         mScrollbar[VERTICAL]->setDocSize( doc_height );
00574         mScrollbar[VERTICAL]->setPageSize( visible_height );
00575 } // end updateScroll
00576 
00577 void LLScrollableContainerView::setBorderVisible(BOOL b)
00578 {
00579         mBorder->setVisible( b );
00580 }
00581 
00582 // Scroll so that as much of rect as possible is showing (where rect is defined in the space of scroller view, not scrolled)
00583 void LLScrollableContainerView::scrollToShowRect(const LLRect& rect, const LLCoordGL& desired_offset)
00584 {
00585         if (!mScrolledView)
00586         {
00587                 llwarns << "LLScrollableContainerView::scrollToShowRect with no view!" << llendl;
00588                 return;
00589         }
00590 
00591         S32 visible_width = 0;
00592         S32 visible_height = 0;
00593         BOOL show_v_scrollbar = FALSE;
00594         BOOL show_h_scrollbar = FALSE;
00595         const LLRect& scrolled_rect = mScrolledView->getRect();
00596         calcVisibleSize( scrolled_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
00597 
00598         // can't be so far left that right side of rect goes off screen, or so far right that left side does
00599         S32 horiz_offset = llclamp(desired_offset.mX, llmin(0, -visible_width + rect.getWidth()), 0);
00600         // can't be so high that bottom of rect goes off screen, or so low that top does
00601         S32 vert_offset = llclamp(desired_offset.mY, 0, llmax(0, visible_height - rect.getHeight()));
00602 
00603         // Vertical
00604         // 1. First make sure the top is visible
00605         // 2. Then, if possible without hiding the top, make the bottom visible.
00606         S32 vert_pos = mScrollbar[VERTICAL]->getDocPos();
00607 
00608         // find scrollbar position to get top of rect on screen (scrolling up)
00609         S32 top_offset = scrolled_rect.mTop - rect.mTop - vert_offset;
00610         // find scrollbar position to get bottom of rect on screen (scrolling down)
00611         S32 bottom_offset = vert_offset == 0 ? scrolled_rect.mTop - rect.mBottom - visible_height : top_offset;
00612         // scroll up far enough to see top or scroll down just enough if item is bigger than visual area
00613         if( vert_pos >= top_offset || visible_height < rect.getHeight())
00614         {
00615                 vert_pos = top_offset;
00616         }
00617         // else scroll down far enough to see bottom
00618         else
00619         if( vert_pos <= bottom_offset )
00620         {
00621                 vert_pos = bottom_offset;
00622         }
00623 
00624         mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() );
00625         mScrollbar[VERTICAL]->setPageSize( visible_height );
00626         mScrollbar[VERTICAL]->setDocPos( vert_pos );
00627 
00628         // Horizontal
00629         // 1. First make sure left side is visible
00630         // 2. Then, if possible without hiding the left side, make the right side visible.
00631         S32 horiz_pos = mScrollbar[HORIZONTAL]->getDocPos();
00632         S32 left_offset = rect.mLeft - scrolled_rect.mLeft + horiz_offset;
00633         S32 right_offset = horiz_offset == 0 ? rect.mRight - scrolled_rect.mLeft - visible_width : left_offset;
00634 
00635         if( horiz_pos >= left_offset || visible_width < rect.getWidth() )
00636         {
00637                 horiz_pos = left_offset;
00638         }
00639         else if( horiz_pos <= right_offset )
00640         {
00641                 horiz_pos = right_offset;
00642         }
00643         
00644         mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() );
00645         mScrollbar[HORIZONTAL]->setPageSize( visible_width );
00646         mScrollbar[HORIZONTAL]->setDocPos( horiz_pos );
00647 
00648         // propagate scroll to document
00649         updateScroll();
00650 }
00651 
00652 void LLScrollableContainerView::pageUp(S32 overlap)
00653 {
00654         mScrollbar[VERTICAL]->pageUp(overlap);
00655 }
00656 
00657 void LLScrollableContainerView::pageDown(S32 overlap)
00658 {
00659         mScrollbar[VERTICAL]->pageDown(overlap);
00660 }
00661 
00662 void LLScrollableContainerView::goToTop()
00663 {
00664         mScrollbar[VERTICAL]->setDocPos(0);
00665 }
00666 
00667 void LLScrollableContainerView::goToBottom()
00668 {
00669         mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocSize());
00670 }
00671 
00672 S32 LLScrollableContainerView::getBorderWidth() const
00673 {
00674         if (mBorder)
00675         {
00676                 return mBorder->getBorderWidth();
00677         }
00678 
00679         return 0;
00680 }
00681 
00682 // virtual
00683 LLXMLNodePtr LLScrollableContainerView::getXML(bool save_children) const
00684 {
00685         LLXMLNodePtr node = LLView::getXML();
00686 
00687         // Attributes
00688 
00689         node->createChild("opaque", TRUE)->setBoolValue(mIsOpaque);
00690 
00691         if (mIsOpaque)
00692         {
00693                 node->createChild("color", TRUE)->setFloatValue(4, mBackgroundColor.mV);
00694         }
00695 
00696         // Contents
00697 
00698         LLXMLNodePtr child_node = mScrolledView->getXML();
00699 
00700         node->addChild(child_node);
00701 
00702         return node;
00703 }
00704 
00705 LLView* LLScrollableContainerView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
00706 {
00707         LLString name("scroll_container");
00708         node->getAttributeString("name", name);
00709 
00710         LLRect rect;
00711         createRect(node, rect, parent, LLRect());
00712         
00713         BOOL opaque = FALSE;
00714         node->getAttributeBOOL("opaque", opaque);
00715 
00716         LLColor4 color(0,0,0,0);
00717         LLUICtrlFactory::getAttributeColor(node,"color", color);
00718 
00719         // Create the scroll view
00720         LLScrollableContainerView *ret = new LLScrollableContainerView(name, rect, (LLPanel*)NULL, opaque, color);
00721 
00722         LLPanel* panelp = NULL;
00723 
00724         // Find a child panel to add
00725         LLXMLNodePtr child;
00726         for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
00727         {
00728                 LLView *control = factory->createCtrlWidget(panelp, child);
00729                 if (control && control->isPanel())
00730                 {
00731                         if (panelp)
00732                         {
00733                                 llinfos << "Warning! Attempting to put multiple panels into a scrollable container view!" << llendl;
00734                                 delete control;
00735                         }
00736                         else
00737                         {
00738                                 panelp = (LLPanel*)control;
00739                         }
00740                 }
00741         }
00742 
00743         if (panelp == NULL)
00744         {
00745                 panelp = new LLPanel("dummy", LLRect::null, FALSE);
00746         }
00747 
00748         ret->mScrolledView = panelp;
00749 
00750         return ret;
00751 }

Generated on Fri May 16 08:32:56 2008 for SecondLife by  doxygen 1.5.5