// LLView functionality void LLScrollContainer::reshape(S32 width, S32 height, BOOL called_from_parent) { LLUICtrl::reshape( width, height, called_from_parent ); mInnerRect = getLocalRect(); mInnerRect.stretch( -getBorderWidth() ); if (mScrolledView) { const LLRect& scrolled_rect = mScrolledView->getRect(); S32 visible_width = 0; S32 visible_height = 0; BOOL show_v_scrollbar = FALSE; BOOL show_h_scrollbar = FALSE; calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() ); mScrollbar[VERTICAL]->setPageSize( visible_height ); mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() ); mScrollbar[HORIZONTAL]->setPageSize( visible_width ); updateScroll(); } }
LLRect LLScrollContainer::getContentWindowRect() { updateScroll(); LLRect scroller_view_rect; S32 visible_width = 0; S32 visible_height = 0; BOOL show_h_scrollbar = FALSE; BOOL show_v_scrollbar = FALSE; calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); S32 border_width = getBorderWidth(); scroller_view_rect.setOriginAndSize(border_width, show_h_scrollbar ? mScrollbar[HORIZONTAL]->getRect().mTop : border_width, visible_width, visible_height); return scroller_view_rect; }
void LLScrollContainer::updateScroll() { if (!mScrolledView) { return; } static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); LLRect doc_rect = mScrolledView->getRect(); S32 doc_width = doc_rect.getWidth(); S32 doc_height = doc_rect.getHeight(); S32 visible_width = 0; S32 visible_height = 0; BOOL show_v_scrollbar = FALSE; BOOL show_h_scrollbar = FALSE; calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); S32 border_width = getBorderWidth(); if( show_v_scrollbar ) { if( doc_rect.mTop < getRect().getHeight() - border_width ) { mScrolledView->translate( 0, getRect().getHeight() - border_width - doc_rect.mTop ); } scrollVertical( mScrollbar[VERTICAL]->getDocPos() ); mScrollbar[VERTICAL]->setVisible( TRUE ); S32 v_scrollbar_height = visible_height; if( !show_h_scrollbar && mReserveScrollCorner ) { v_scrollbar_height -= scrollbar_size; } mScrollbar[VERTICAL]->reshape( scrollbar_size, v_scrollbar_height, TRUE ); // Make room for the horizontal scrollbar (or not) S32 v_scrollbar_offset = 0; if( show_h_scrollbar || mReserveScrollCorner ) { v_scrollbar_offset = scrollbar_size; } LLRect r = mScrollbar[VERTICAL]->getRect(); r.translate( 0, mInnerRect.mBottom - r.mBottom + v_scrollbar_offset ); mScrollbar[VERTICAL]->setRect( r ); } else { mScrolledView->translate( 0, getRect().getHeight() - border_width - doc_rect.mTop ); mScrollbar[VERTICAL]->setVisible( FALSE ); mScrollbar[VERTICAL]->setDocPos( 0 ); } if( show_h_scrollbar ) { if( doc_rect.mLeft > border_width ) { mScrolledView->translate( border_width - doc_rect.mLeft, 0 ); mScrollbar[HORIZONTAL]->setDocPos( 0 ); } else { scrollHorizontal( mScrollbar[HORIZONTAL]->getDocPos() ); } mScrollbar[HORIZONTAL]->setVisible( TRUE ); S32 h_scrollbar_width = visible_width; if( !show_v_scrollbar && mReserveScrollCorner ) { h_scrollbar_width -= scrollbar_size; } mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, scrollbar_size, TRUE ); } else { mScrolledView->translate( border_width - doc_rect.mLeft, 0 ); mScrollbar[HORIZONTAL]->setVisible( FALSE ); mScrollbar[HORIZONTAL]->setDocPos( 0 ); } mScrollbar[HORIZONTAL]->setDocSize( doc_width ); mScrollbar[HORIZONTAL]->setPageSize( visible_width ); mScrollbar[VERTICAL]->setDocSize( doc_height ); mScrollbar[VERTICAL]->setPageSize( visible_height ); } // end updateScroll
void LLScrollContainer::draw() { static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); if (mAutoScrolling) { // add acceleration to autoscroll mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), mMaxAutoScrollRate); } else { // reset to minimum for next time mAutoScrollRate = mMinAutoScrollRate; } // clear this flag to be set on next call to autoScroll mAutoScrolling = FALSE; // auto-focus when scrollbar active // this allows us to capture user intent (i.e. stop automatically scrolling the view/etc) if (!hasFocus() && (mScrollbar[VERTICAL]->hasMouseCapture() || mScrollbar[HORIZONTAL]->hasMouseCapture())) { focusFirstItem(); } // Draw background if( mIsOpaque ) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4fv( mBackgroundColor.get().mV ); gl_rect_2d( mInnerRect ); } // Draw mScrolledViews and update scroll bars. // get a scissor region ready, and draw the scrolling view. The // scissor region ensures that we don't draw outside of the bounds // of the rectangle. if( mScrolledView ) { updateScroll(); // Draw the scrolled area. { S32 visible_width = 0; S32 visible_height = 0; BOOL show_v_scrollbar = FALSE; BOOL show_h_scrollbar = FALSE; calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); LLLocalClipRect clip(LLRect(mInnerRect.mLeft, mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height, mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0), mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) )); drawChild(mScrolledView); } } // Highlight border if a child of this container has keyboard focus if( mBorder->getVisible() ) { mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) ); } // Draw all children except mScrolledView // Note: scrollbars have been adjusted by above drawing code for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin(); child_iter != getChildList()->rend(); ++child_iter) { LLView *viewp = *child_iter; if( sDebugRects ) { sDepth++; } if( (viewp != mScrolledView) && viewp->getVisible() ) { drawChild(viewp); } if( sDebugRects ) { sDepth--; } } } // end draw
// Scroll so that as much of rect as possible is showing (where rect is defined in the space of scroller view, not scrolled) void LLScrollableContainerView::scrollToShowRect(const LLRect& rect, const LLCoordGL& desired_offset) { if (!mScrolledView) { llwarns << "LLScrollableContainerView::scrollToShowRect with no view!" << llendl; return; } S32 visible_width = 0; S32 visible_height = 0; BOOL show_v_scrollbar = FALSE; BOOL show_h_scrollbar = FALSE; const LLRect& scrolled_rect = mScrolledView->getRect(); calcVisibleSize( scrolled_rect, &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); // can't be so far left that right side of rect goes off screen, or so far right that left side does S32 horiz_offset = llclamp(desired_offset.mX, llmin(0, -visible_width + rect.getWidth()), 0); // can't be so high that bottom of rect goes off screen, or so low that top does S32 vert_offset = llclamp(desired_offset.mY, 0, llmax(0, visible_height - rect.getHeight())); // Vertical // 1. First make sure the top is visible // 2. Then, if possible without hiding the top, make the bottom visible. S32 vert_pos = mScrollbar[VERTICAL]->getDocPos(); // find scrollbar position to get top of rect on screen (scrolling up) S32 top_offset = scrolled_rect.mTop - rect.mTop - vert_offset; // find scrollbar position to get bottom of rect on screen (scrolling down) S32 bottom_offset = vert_offset == 0 ? scrolled_rect.mTop - rect.mBottom - visible_height : top_offset; // scroll up far enough to see top or scroll down just enough if item is bigger than visual area if( vert_pos >= top_offset || visible_height < rect.getHeight()) { vert_pos = top_offset; } // else scroll down far enough to see bottom else if( vert_pos <= bottom_offset ) { vert_pos = bottom_offset; } mScrollbar[VERTICAL]->setDocSize( scrolled_rect.getHeight() ); mScrollbar[VERTICAL]->setPageSize( visible_height ); mScrollbar[VERTICAL]->setDocPos( vert_pos ); // Horizontal // 1. First make sure left side is visible // 2. Then, if possible without hiding the left side, make the right side visible. S32 horiz_pos = mScrollbar[HORIZONTAL]->getDocPos(); S32 left_offset = rect.mLeft - scrolled_rect.mLeft + horiz_offset; S32 right_offset = horiz_offset == 0 ? rect.mRight - scrolled_rect.mLeft - visible_width : left_offset; if( horiz_pos >= left_offset || visible_width < rect.getWidth() ) { horiz_pos = left_offset; } else if( horiz_pos <= right_offset ) { horiz_pos = right_offset; } mScrollbar[HORIZONTAL]->setDocSize( scrolled_rect.getWidth() ); mScrollbar[HORIZONTAL]->setPageSize( visible_width ); mScrollbar[HORIZONTAL]->setDocPos( horiz_pos ); // propagate scroll to document updateScroll(); }
void LLScrollableContainerView::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const { const LLRect& rect = mScrolledView->getRect(); calcVisibleSize(rect, visible_width, visible_height, show_h_scrollbar, show_v_scrollbar); }