llscrollcontainer.cpp

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

Generated on Thu Jul 1 06:09:05 2010 for Second Life Viewer by  doxygen 1.4.7