diff options
Diffstat (limited to 'indra/llui/lltextbase.cpp')
-rw-r--r-- | indra/llui/lltextbase.cpp | 110 |
1 files changed, 80 insertions, 30 deletions
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 333513d7d7..1cc3cc04d6 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -157,6 +157,7 @@ LLTextBase::Params::Params() read_only("read_only", false), v_pad("v_pad", 0), h_pad("h_pad", 0), + clip("clip", true), clip_partial("clip_partial", true), line_spacing("line_spacing"), max_text_length("max_length", 255), @@ -199,6 +200,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mVAlign(p.font_valign), mLineSpacingMult(p.line_spacing.multiple), mLineSpacingPixels(p.line_spacing.pixels), + mClip(p.clip), mClipPartial(p.clip_partial && !p.allow_scroll), mTrackEnd( p.track_end ), mScrollIndex(-1), @@ -334,7 +336,7 @@ void LLTextBase::drawSelectionBackground() // binary search for line that starts before top of visible buffer line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom()); - line_list_t::const_iterator end_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top()); + line_list_t::const_iterator end_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top()); bool done = false; @@ -512,7 +514,6 @@ void LLTextBase::drawText() selection_right = llmax( mSelectionStart, mSelectionEnd ); } - LLRect scrolled_view_rect = getVisibleDocumentRect(); std::pair<S32, S32> line_range = getVisibleLines(mClipPartial); S32 first_line = line_range.first; S32 last_line = line_range.second; @@ -545,10 +546,10 @@ void LLTextBase::drawText() line_end = next_start; } - LLRect text_rect(line.mRect.mLeft + mVisibleTextRect.mLeft - scrolled_view_rect.mLeft, - line.mRect.mTop - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom, - llmin(mDocumentView->getRect().getWidth(), line.mRect.mRight) - scrolled_view_rect.mLeft, - line.mRect.mBottom - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom); + LLRect text_rect(line.mRect); + text_rect.mRight = llmin(mDocumentView->getRect().getWidth(), text_rect.mRight); // clamp right edge to document extents + text_rect.translate(mVisibleTextRect.mLeft, mVisibleTextRect.mBottom); // translate into display region of text widget + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position // draw a single line of text S32 seg_start = line_start; @@ -993,14 +994,28 @@ void LLTextBase::draw() updateScrollFromCursor(); } - LLRect doc_rect; + LLRect text_rect; if (mScroller) { - mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &doc_rect, this); + mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &text_rect, this); } else { - doc_rect = getLocalRect(); + LLRect visible_lines_rect; + std::pair<S32, S32> line_range = getVisibleLines(mClipPartial); + for (S32 i = line_range.first; i < line_range.second; i++) + { + if (visible_lines_rect.isEmpty()) + { + visible_lines_rect = mLineInfoList[i].mRect; + } + else + { + visible_lines_rect.unionWith(mLineInfoList[i].mRect); + } + } + text_rect = visible_lines_rect; + text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); } if (mBGVisible) @@ -1010,28 +1025,37 @@ void LLTextBase::draw() LLRect bg_rect = mVisibleTextRect; if (mScroller) { - bg_rect.intersectWith(doc_rect); + bg_rect.intersectWith(text_rect); } LLColor4 bg_color = mReadOnly ? mReadOnlyBgColor.get() : hasFocus() ? mFocusBgColor.get() : mWriteableBgColor.get(); - gl_rect_2d(doc_rect, bg_color % alpha, TRUE); + gl_rect_2d(text_rect, bg_color % alpha, TRUE); } - // draw document view - LLUICtrl::draw(); - - { - // only clip if we support scrolling... - // since convention is that text boxes never vertically truncate their contents - // regardless of rect bounds - LLLocalClipRect clip(doc_rect, mScroller != NULL); + bool should_clip = mClip || mScroller != NULL; + { LLLocalClipRect clip(text_rect, should_clip); + + // draw document view + if (mScroller) + { + drawChild(mScroller); + } + else + { + drawChild(mDocumentView); + } + drawSelectionBackground(); drawText(); drawCursor(); } + + mDocumentView->setVisible(FALSE); + LLUICtrl::draw(); + mDocumentView->setVisible(TRUE); } @@ -1140,7 +1164,7 @@ void LLTextBase::reflow() S32 first_line = getFirstVisibleLine(); // if scroll anchor not on first line, update it to first character of first line - if (!mLineInfoList.empty() + if ((first_line < mLineInfoList.size()) && (mScrollIndex < mLineInfoList[first_line].mDocIndexStart || mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd)) { @@ -1415,7 +1439,7 @@ S32 LLTextBase::getFirstVisibleLine() const return iter - mLineInfoList.begin(); } -std::pair<S32, S32> LLTextBase::getVisibleLines(bool fully_visible) +std::pair<S32, S32> LLTextBase::getVisibleLines(bool require_fully_visible) { LLRect visible_region = getVisibleDocumentRect(); line_list_t::const_iterator first_iter; @@ -1424,14 +1448,14 @@ std::pair<S32, S32> LLTextBase::getVisibleLines(bool fully_visible) // make sure we have an up-to-date mLineInfoList reflow(); - if (fully_visible) + if (require_fully_visible) { first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_top()); - last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom()); + last_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom()); } else { - first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom()); + first_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom()); last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top()); } return std::pair<S32, S32>(first_iter - mLineInfoList.begin(), last_iter - mLineInfoList.begin()); @@ -1997,11 +2021,10 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, pos = segment_line_start + offset; break; } - else if (hit_past_end_of_line && segmentp->getEnd() > line_iter->mDocIndexEnd - 1) + else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd) { // segment wraps to next line, so just set doc pos to the end of the line - // segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd) - pos = llmin(getLength(), line_iter->mDocIndexEnd); + pos = llclamp(line_iter->mDocIndexEnd - 1, 0, getLength()); break; } start_x += text_width; @@ -2404,14 +2427,41 @@ LLRect LLTextBase::getVisibleDocumentRect() const { return mScroller->getVisibleContentRect(); } - else + else if (mClip) { - // entire document rect is visible when not scrolling + LLRect visible_text_rect = getVisibleTextRect(); + LLRect doc_rect = mDocumentView->getRect(); + visible_text_rect.translate(-doc_rect.mLeft, -doc_rect.mBottom); + + // reject partially visible lines + LLRect visible_lines_rect; + for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end(); + it != end_it; + ++it) + { + bool line_visible = mClipPartial ? visible_text_rect.contains(it->mRect) : visible_text_rect.overlaps(it->mRect); + if (line_visible) + { + if (visible_lines_rect.isEmpty()) + { + visible_lines_rect = it->mRect; + } + else + { + visible_lines_rect.unionWith(it->mRect); + } + } + } + return visible_lines_rect; + } + else + { // entire document rect is visible // but offset according to height of widget + LLRect doc_rect = mDocumentView->getLocalRect(); doc_rect.mLeft -= mDocumentView->getRect().mLeft; // adjust for height of text above widget baseline - doc_rect.mBottom = doc_rect.getHeight() - mVisibleTextRect.getHeight(); + doc_rect.mBottom = llmin(0, doc_rect.getHeight() - mVisibleTextRect.getHeight()); return doc_rect; } } |