void LLScrollbar::updateThumbRect() { // llassert( 0 <= mDocSize ); // llassert( 0 <= mDocPos && mDocPos <= getDocPosMax() ); const S32 THUMB_MIN_LENGTH = 16; S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight(); S32 thumb_bg_length = llmax(0, window_length - 2 * SCROLLBAR_SIZE); S32 visible_lines = llmin( mDocSize, mPageSize ); S32 thumb_length = mDocSize ? llmin(llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH), thumb_bg_length) : thumb_bg_length; S32 variable_lines = mDocSize - visible_lines; if( mOrientation == LLScrollbar::VERTICAL ) { S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE; S32 thumb_start_min = SCROLLBAR_SIZE + THUMB_MIN_LENGTH; S32 thumb_start = variable_lines ? llmin( llmax(thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_max; mThumbRect.mLeft = 0; mThumbRect.mTop = thumb_start; mThumbRect.mRight = SCROLLBAR_SIZE; mThumbRect.mBottom = thumb_start - thumb_length; } else { // Horizontal S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE - thumb_length; S32 thumb_start_min = SCROLLBAR_SIZE; S32 thumb_start = variable_lines ? llmin(llmax( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_min; mThumbRect.mLeft = thumb_start; mThumbRect.mTop = SCROLLBAR_SIZE; mThumbRect.mRight = thumb_start + thumb_length; mThumbRect.mBottom = 0; } if (mOnScrollEndCallback && mOnScrollEndData && (mDocPos == getDocPosMax())) { mOnScrollEndCallback(mOnScrollEndData); } }
void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb) { pos = llclamp(pos, 0, getDocPosMax()); if (pos != mDocPos) { mDocPos = pos; mDocChanged = TRUE; if( mChangeCallback ) { mChangeCallback( mDocPos, this, mCallbackUserData ); } if( update_thumb ) { updateThumbRect(); } } }
// returns true if document position really changed bool LLScrollbar::setDocPos(S32 pos, BOOL update_thumb) { pos = llclamp(pos, 0, getDocPosMax()); if (pos != mDocPos) { mDocPos = pos; mDocChanged = TRUE; if( mChangeCallback ) { mChangeCallback( mDocPos, this ); } if( update_thumb ) { updateThumbRect(); } return true; } return false; }
BOOL LLScrollbar::handleKeyHere(KEY key, MASK mask) { BOOL handled = FALSE; switch( key ) { case KEY_HOME: setDocPos( 0 ); handled = TRUE; break; case KEY_END: setDocPos( getDocPosMax() ); handled = TRUE; break; case KEY_DOWN: setDocPos( getDocPos() + mStepSize ); handled = TRUE; break; case KEY_UP: setDocPos( getDocPos() - mStepSize ); handled = TRUE; break; case KEY_PAGE_DOWN: pageDown(1); break; case KEY_PAGE_UP: pageUp(1); break; } return handled; }
void LLScrollbar::draw() { if (!getRect().isValid()) return; S32 local_mouse_x; S32 local_mouse_y; LLUI::getCursorPositionLocal(this, &local_mouse_x, &local_mouse_y); BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this; BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y)); if (hovered) { mCurGlowStrength = lerp(mCurGlowStrength, mHoverGlowStrength, LLCriticalDamp::getInterpolant(0.05f)); } else { mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLCriticalDamp::getInterpolant(0.05f)); } // Draw background and thumb. LLUIImage* rounded_rect_imagep = LLUI::sImageProvider->getUIImage("rounded_square.tga"); if (!rounded_rect_imagep) { gl_rect_2d(mOrientation == HORIZONTAL ? SCROLLBAR_SIZE : 0, mOrientation == VERTICAL ? getRect().getHeight() - 2 * SCROLLBAR_SIZE : getRect().getHeight(), mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * SCROLLBAR_SIZE : getRect().getWidth(), mOrientation == VERTICAL ? SCROLLBAR_SIZE : 0, mTrackColor, TRUE); gl_rect_2d(mThumbRect, mThumbColor, TRUE); } else { // Background rounded_rect_imagep->drawSolid(mOrientation == HORIZONTAL ? SCROLLBAR_SIZE : 0, mOrientation == VERTICAL ? SCROLLBAR_SIZE : 0, mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * SCROLLBAR_SIZE : getRect().getWidth(), mOrientation == VERTICAL ? getRect().getHeight() - 2 * SCROLLBAR_SIZE : getRect().getHeight(), mTrackColor); // Thumb LLRect outline_rect = mThumbRect; outline_rect.stretch(2); if (gFocusMgr.getKeyboardFocus() == this) { rounded_rect_imagep->draw(outline_rect, gFocusMgr.getFocusColor()); } rounded_rect_imagep->draw(mThumbRect, mThumbColor); if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); rounded_rect_imagep->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength)); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } BOOL was_scrolled_to_bottom = (getDocPos() == getDocPosMax()); if (mOnScrollEndCallback && was_scrolled_to_bottom) { mOnScrollEndCallback(mOnScrollEndData); } // Draw children LLView::draw(); } // end draw
BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) { // Note: we don't bother sending the event to the children (the arrow buttons) // because they'll capture the mouse whenever they need hover events. BOOL handled = FALSE; if( hasMouseCapture() ) { S32 height = getRect().getHeight(); S32 width = getRect().getWidth(); if( VERTICAL == mOrientation ) { // S32 old_pos = mThumbRect.mTop; S32 delta_pixels = y - mDragStartY; if( mOrigRect.mBottom + delta_pixels < SCROLLBAR_SIZE ) { delta_pixels = SCROLLBAR_SIZE - mOrigRect.mBottom - 1; } else if( mOrigRect.mTop + delta_pixels > height - SCROLLBAR_SIZE ) { delta_pixels = height - SCROLLBAR_SIZE - mOrigRect.mTop + 1; } mThumbRect.mTop = mOrigRect.mTop + delta_pixels; mThumbRect.mBottom = mOrigRect.mBottom + delta_pixels; S32 thumb_length = mThumbRect.getHeight(); S32 thumb_track_length = height - 2 * SCROLLBAR_SIZE; if( delta_pixels != mLastDelta || mDocChanged) { // Note: delta_pixels increases as you go up. mDocPos increases down (line 0 is at the top of the page). S32 usable_track_length = thumb_track_length - thumb_length; if( 0 < usable_track_length ) { S32 variable_lines = getDocPosMax(); S32 pos = mThumbRect.mTop; F32 ratio = F32(pos - SCROLLBAR_SIZE - thumb_length) / usable_track_length; S32 new_pos = llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines ); // Note: we do not call updateThumbRect() here. Instead we let the thumb and the document go slightly // out of sync (less than a line's worth) to make the thumb feel responsive. changeLine( new_pos - mDocPos, FALSE ); } } mLastDelta = delta_pixels; } else { // Horizontal // S32 old_pos = mThumbRect.mLeft; S32 delta_pixels = x - mDragStartX; if( mOrigRect.mLeft + delta_pixels < SCROLLBAR_SIZE ) { delta_pixels = SCROLLBAR_SIZE - mOrigRect.mLeft - 1; } else if( mOrigRect.mRight + delta_pixels > width - SCROLLBAR_SIZE ) { delta_pixels = width - SCROLLBAR_SIZE - mOrigRect.mRight + 1; } mThumbRect.mLeft = mOrigRect.mLeft + delta_pixels; mThumbRect.mRight = mOrigRect.mRight + delta_pixels; S32 thumb_length = mThumbRect.getWidth(); S32 thumb_track_length = width - 2 * SCROLLBAR_SIZE; if( delta_pixels != mLastDelta || mDocChanged) { // Note: delta_pixels increases as you go up. mDocPos increases down (line 0 is at the top of the page). S32 usable_track_length = thumb_track_length - thumb_length; if( 0 < usable_track_length ) { S32 variable_lines = getDocPosMax(); S32 pos = mThumbRect.mLeft; F32 ratio = F32(pos - SCROLLBAR_SIZE) / usable_track_length; S32 new_pos = llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines); // Note: we do not call updateThumbRect() here. Instead we let the thumb and the document go slightly // out of sync (less than a line's worth) to make the thumb feel responsive. changeLine( new_pos - mDocPos, FALSE ); } } mLastDelta = delta_pixels; } getWindow()->setCursor(UI_CURSOR_ARROW); lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; handled = TRUE; } else { handled = childrenHandleMouseUp( x, y, mask ) != NULL; } // Opaque if( !handled ) { getWindow()->setCursor(UI_CURSOR_ARROW); lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; handled = TRUE; } mDocChanged = FALSE; return handled; } // end handleHover
BOOL LLScrollbar::isAtEnd() { return mDocPos == getDocPosMax(); }