From 606311b508c5b13cd995a98d16660e61a58fa3f7 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Mon, 5 Oct 2009 20:53:51 +0000 Subject: text boxes are now *not* mouse_opaque by default fixed some textbox and text editor layout problems (getWidth called with wrong index) EXT-1302 - rewrite LLExpandableTextBox to use new LLTextBase functionality (using custom LLExpanderSegment) reviewed by James --- indra/llui/llscrolllistctrl.cpp | 2 +- indra/llui/lltextbase.cpp | 317 ++++++++++++++++++++++++---------------- indra/llui/lltextbase.h | 4 +- indra/llui/lltextbox.cpp | 75 +++------- indra/llui/lltextbox.h | 1 - 5 files changed, 212 insertions(+), 187 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index af05686c70..7b74b1f93b 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1566,7 +1566,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, MASK mask) LLToolTipMgr::instance().show(LLToolTip::Params() .message(hit_cell->getValue().asString()) .font(LLFontGL::getFontSansSerifSmall()) - .pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 4)) + .pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 6)) .delay_time(0.2f) .sticky_rect(sticky_rect)); } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 6c048aa908..62f03f47e6 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -209,7 +209,8 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mWordWrap(p.wrap), mUseEllipses( p.use_ellipses ), mParseHTML(p.allow_html), - mParseHighlights(p.parse_highlights) + mParseHighlights(p.parse_highlights), + mHideScrollbar(p.hide_scrollbar) { LLScrollContainer::Params scroll_params; scroll_params.name = "text scroller"; @@ -278,7 +279,9 @@ bool LLTextBase::truncate() // Truncate safely in UTF-8 std::string temp_utf8_text = wstring_to_utf8str(text); temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength ); - getViewModel()->setDisplay(utf8str_to_wstring( temp_utf8_text )); + LLWString text = utf8str_to_wstring( temp_utf8_text ); + // remove extra bit of current string, to preserve formatting, etc. + removeStringNoUndo(text.size(), getWText().size() - text.size()); did_truncate = TRUE; } } @@ -755,47 +758,60 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) // split old at start point for new segment cur_segmentp->setEnd(segment_to_insert->getStart()); // advance to next segment - ++cur_seg_iter; // insert remainder of old segment LLTextSegmentPtr remainder_segment = new LLNormalTextSegment( cur_segmentp->getStyle(), segment_to_insert->getStart(), old_segment_end, *this); - cur_seg_iter = mSegments.insert(cur_seg_iter, remainder_segment); + mSegments.insert(cur_seg_iter, remainder_segment); remainder_segment->linkToDocument(this); // insert new segment before remainder of old segment - cur_seg_iter = mSegments.insert(cur_seg_iter, segment_to_insert); + mSegments.insert(cur_seg_iter, segment_to_insert); segment_to_insert->linkToDocument(this); - // move to "remanider" segment and start truncation there - ++cur_seg_iter; + // at this point, there will be two overlapping segments owning the text + // associated with the incoming segment } else { - cur_seg_iter = mSegments.insert(cur_seg_iter, segment_to_insert); - ++cur_seg_iter; + mSegments.insert(cur_seg_iter, segment_to_insert); segment_to_insert->linkToDocument(this); } // now delete/truncate remaining segments as necessary + // cur_seg_iter points to segment before incoming segment while(cur_seg_iter != mSegments.end()) { cur_segmentp = *cur_seg_iter; - if (cur_segmentp->getEnd() <= segment_to_insert->getEnd()) + if (cur_segmentp == segment_to_insert) { - cur_segmentp->unlinkFromDocument(this); - segment_set_t::iterator seg_to_erase(cur_seg_iter++); - mSegments.erase(seg_to_erase); + ++cur_seg_iter; + continue; } - else + + if (cur_segmentp->getStart() >= segment_to_insert->getStart()) { - cur_segmentp->setStart(segment_to_insert->getEnd()); - break; + if(cur_segmentp->getEnd() <= segment_to_insert->getEnd()) + { + cur_segmentp->unlinkFromDocument(this); + // grab copy of iterator to erase, and bump it + segment_set_t::iterator seg_to_erase(cur_seg_iter++); + mSegments.erase(seg_to_erase); + continue; + } + else + { + // last overlapping segment, clip to end of incoming segment + // and stop traversal + cur_segmentp->setStart(segment_to_insert->getEnd()); + break; + } } + ++cur_seg_iter; } } } BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleMouseDown(x, y, mask)) { return TRUE; @@ -806,7 +822,7 @@ BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleMouseUp(x, y, mask)) { // Did we just click on a link? @@ -824,7 +840,7 @@ BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleMiddleMouseDown(x, y, mask)) { return TRUE; @@ -835,7 +851,7 @@ BOOL LLTextBase::handleMiddleMouseDown(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleMiddleMouseUp(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleMiddleMouseUp(x, y, mask)) { return TRUE; @@ -846,7 +862,7 @@ BOOL LLTextBase::handleMiddleMouseUp(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleRightMouseDown(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleRightMouseDown(x, y, mask)) { return TRUE; @@ -857,7 +873,7 @@ BOOL LLTextBase::handleRightMouseDown(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleRightMouseUp(x, y, mask)) { return TRUE; @@ -868,7 +884,7 @@ BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleDoubleClick(x, y, mask)) { return TRUE; @@ -879,7 +895,7 @@ BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleHover(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleHover(x, y, mask)) { return TRUE; @@ -890,7 +906,7 @@ BOOL LLTextBase::handleHover(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleScrollWheel(S32 x, S32 y, S32 clicks) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleScrollWheel(x, y, clicks)) { return TRUE; @@ -901,7 +917,7 @@ BOOL LLTextBase::handleScrollWheel(S32 x, S32 y, S32 clicks) BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask) { - LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleToolTip(x, y, mask)) { return TRUE; @@ -1040,109 +1056,106 @@ void LLTextBase::reflow(S32 start_index) S32 cur_top = 0; - if (getLength()) + segment_set_t::iterator seg_iter = mSegments.begin(); + S32 seg_offset = 0; + S32 line_start_index = 0; + const S32 text_width = mTextRect.getWidth(); // optionally reserve room for margin + S32 remaining_pixels = text_width; + LLWString text(getWText()); + S32 line_count = 0; + + // find and erase line info structs starting at start_index and going to end of document + if (!mLineInfoList.empty()) { - segment_set_t::iterator seg_iter = mSegments.begin(); - S32 seg_offset = 0; - S32 line_start_index = 0; - const S32 text_width = mTextRect.getWidth(); // optionally reserve room for margin - S32 remaining_pixels = text_width; - LLWString text(getWText()); - S32 line_count = 0; - - // find and erase line info structs starting at start_index and going to end of document - if (!mLineInfoList.empty()) - { - // find first element whose end comes after start_index - line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare()); - line_start_index = iter->mDocIndexStart; - line_count = iter->mLineNum; - getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset); - mLineInfoList.erase(iter, mLineInfoList.end()); - } + // find first element whose end comes after start_index + line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare()); + line_start_index = iter->mDocIndexStart; + line_count = iter->mLineNum; + getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset); + mLineInfoList.erase(iter, mLineInfoList.end()); + } - S32 line_height = 0; + S32 line_height = 0; - while(seg_iter != mSegments.end()) + while(seg_iter != mSegments.end()) + { + LLTextSegmentPtr segment = *seg_iter; + + // track maximum height of any segment on this line + line_height = llmax(line_height, segment->getMaxHeight()); + S32 cur_index = segment->getStart() + seg_offset; + // find run of text from this segment that we can display on one line + S32 end_index = cur_index; + while(end_index < segment->getEnd() && text[end_index] != '\n') { - LLTextSegmentPtr segment = *seg_iter; - - // track maximum height of any segment on this line - line_height = llmax(line_height, segment->getMaxHeight()); - S32 cur_index = segment->getStart() + seg_offset; - // find run of text from this segment that we can display on one line - S32 end_index = cur_index; - while(end_index < segment->getEnd() && text[end_index] != '\n') - { - ++end_index; - } - - // ask segment how many character fit in remaining space - S32 max_characters = end_index - cur_index; - S32 character_count = segment->getNumChars(getWordWrap() ? llmax(0, remaining_pixels) : S32_MAX, - seg_offset, - cur_index - line_start_index, - max_characters); - + ++end_index; + } - S32 segment_width = segment->getWidth(seg_offset, character_count); - remaining_pixels -= segment_width; - S32 text_left = getLeftOffset(text_width - remaining_pixels); + // ask segment how many character fit in remaining space + S32 max_characters = end_index - cur_index; + S32 character_count = segment->getNumChars(getWordWrap() ? llmax(0, remaining_pixels) : S32_MAX, + seg_offset, + cur_index - line_start_index, + max_characters); + - seg_offset += character_count; + S32 segment_width = segment->getWidth(seg_offset, character_count); + remaining_pixels -= segment_width; + S32 text_left = getLeftOffset(text_width - remaining_pixels); - S32 last_segment_char_on_line = segment->getStart() + seg_offset; + seg_offset += character_count; - // if we didn't finish the current segment... - if (last_segment_char_on_line < segment->getEnd()) - { - // set up index for next line - // ...skip newline, we don't want to draw - S32 next_line_count = line_count; - if (text[last_segment_char_on_line] == '\n') - { - seg_offset++; - last_segment_char_on_line++; - next_line_count++; - } + S32 last_segment_char_on_line = segment->getStart() + seg_offset; - // add line info and keep going - mLineInfoList.push_back(line_info( - line_start_index, - last_segment_char_on_line, - LLRect(text_left, - cur_top, - text_left + (text_width - remaining_pixels), - cur_top - line_height), - line_count)); - - line_start_index = segment->getStart() + seg_offset; - cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; - remaining_pixels = text_width; - line_height = 0; - line_count = next_line_count; - } - // ...just consumed last segment.. - else if (++segment_set_t::iterator(seg_iter) == mSegments.end()) - { - mLineInfoList.push_back(line_info( - line_start_index, - last_segment_char_on_line, - LLRect(text_left, - cur_top, - text_left + (text_width - remaining_pixels), - cur_top - line_height), - line_count)); - cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; - break; - } - // finished a segment and there are segments remaining on this line - else + // if we didn't finish the current segment... + if (last_segment_char_on_line < segment->getEnd()) + { + // set up index for next line + // ...skip newline, we don't want to draw + S32 next_line_count = line_count; + if (text[last_segment_char_on_line] == '\n') { - // subtract pixels used and increment segment - ++seg_iter; - seg_offset = 0; + seg_offset++; + last_segment_char_on_line++; + next_line_count++; } + + // add line info and keep going + mLineInfoList.push_back(line_info( + line_start_index, + last_segment_char_on_line, + LLRect(text_left, + cur_top, + text_left + (text_width - remaining_pixels), + cur_top - line_height), + line_count)); + + line_start_index = segment->getStart() + seg_offset; + cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; + remaining_pixels = text_width; + line_height = 0; + line_count = next_line_count; + } + // ...just consumed last segment.. + else if (++segment_set_t::iterator(seg_iter) == mSegments.end()) + { + mLineInfoList.push_back(line_info( + line_start_index, + last_segment_char_on_line, + LLRect(text_left, + cur_top, + text_left + (text_width - remaining_pixels), + cur_top - line_height), + line_count)); + cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels; + break; + } + // finished a segment and there are segments remaining on this line + else + { + // subtract pixels used and increment segment + ++seg_iter; + seg_offset = 0; } } @@ -1256,6 +1269,19 @@ S32 LLTextBase::getLineStart( S32 line ) const return mLineInfoList[line].mDocIndexStart; } +S32 LLTextBase::getLineEnd( S32 line ) const +{ + S32 num_lines = getLineCount(); + if (num_lines == 0) + { + return 0; + } + + line = llclamp(line, 0, num_lines-1); + return mLineInfoList[line].mDocIndexEnd; +} + + S32 LLTextBase::getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap) const { @@ -1308,14 +1334,27 @@ S32 LLTextBase::getFirstVisibleLine() const return iter - mLineInfoList.begin(); } -std::pair LLTextBase::getVisibleLines() const +std::pair LLTextBase::getVisibleLines(bool fully_visible) { LLRect visible_region = mScroller->getVisibleContentRect(); + line_list_t::const_iterator first_iter; + line_list_t::const_iterator last_iter; - // binary search for line that starts before top of visible buffer and starts before end of visible buffer - line_list_t::const_iterator first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom()); - line_list_t::const_iterator last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top()); + // make sure we have an up-to-date mLineInfoList + reflow(); + if (fully_visible) + { + // binary search for line that starts before top of visible buffer and starts before end of visible buffer + 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()); + } + else + { + // binary search for line that starts before top of visible buffer and starts before end of visible buffer + first_iter = std::lower_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(first_iter - mLineInfoList.begin(), last_iter - mLineInfoList.begin()); } @@ -2147,7 +2186,15 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele S32 start = seg_start; S32 end = llmin( selection_start, seg_end ); S32 length = end - start; - font->render(text, start, rect.mLeft, rect.mTop, color, LLFontGL::LEFT, LLFontGL::TOP, 0, mStyle->getShadowType(), length, rect.getWidth(), &right_x, mEditor.getUseEllipses()); + font->render(text, start, + rect.mLeft, rect.mTop, + color, + LLFontGL::LEFT, LLFontGL::TOP, + 0, + mStyle->getShadowType(), + length, rect.getWidth(), + &right_x, + mEditor.getUseEllipses()); } rect.mLeft = (S32)ceil(right_x); @@ -2158,9 +2205,15 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele S32 end = llmin( selection_end, seg_end ); S32 length = end - start; - font->render(text, start, rect.mLeft, rect.mTop, - LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ), - LLFontGL::LEFT, LLFontGL::TOP, 0, LLFontGL::NO_SHADOW, length, rect.mRight, &right_x, mEditor.getUseEllipses()); + font->render(text, start, + rect.mLeft, rect.mTop, + LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ), + LLFontGL::LEFT, LLFontGL::TOP, + 0, + LLFontGL::NO_SHADOW, + length, rect.mRight, + &right_x, + mEditor.getUseEllipses()); } rect.mLeft = (S32)ceil(right_x); if( selection_end < seg_end ) @@ -2169,7 +2222,15 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele S32 start = llmax( selection_end, seg_start ); S32 end = seg_end; S32 length = end - start; - font->render(text, start, rect.mLeft, rect.mTop, color, LLFontGL::LEFT, LLFontGL::TOP, 0, mStyle->getShadowType(), length, rect.mRight, &right_x, mEditor.getUseEllipses()); + font->render(text, start, + rect.mLeft, rect.mTop, + color, + LLFontGL::LEFT, LLFontGL::TOP, + 0, + mStyle->getShadowType(), + length, rect.mRight, + &right_x, + mEditor.getUseEllipses()); } return right_x; } @@ -2263,7 +2324,7 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin S32 num_chars = mStyle->getFont()->maxDrawableChars(text.c_str() + segment_offset + mStart, (F32)num_pixels, max_chars, - mEditor.getWordWrap()); + TRUE); if (num_chars == 0 && line_offset == 0 diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index d0287a99ca..f20134fd6d 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -277,10 +277,11 @@ protected: // manage lines S32 getLineStart( S32 line ) const; + S32 getLineEnd( S32 line ) const; S32 getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap = true) const; S32 getLineOffsetFromDocIndex( S32 doc_index, bool include_wordwrap = true) const; S32 getFirstVisibleLine() const; - std::pair getVisibleLines() const; + std::pair getVisibleLines(bool fully_visible = false); S32 getLeftOffset(S32 width); void reflow(S32 start_index = 0); @@ -344,6 +345,7 @@ protected: bool mTrackEnd; // if true, keeps scroll position at end of document during resize bool mReadOnly; bool mClip; + bool mHideScrollbar; S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes // support widgets diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 3feca136be..20bceb4675 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -47,26 +47,19 @@ LLTextBox::LLTextBox(const LLTextBox::Params& p) BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = LLTextBase::handleMouseDown(x, y, mask); - // HACK: Only do this if there actually is something to click, so that - // overly large text boxes in the older UI won't start eating clicks. - if (isClickable()) + if (getSoundFlags() & MOUSE_DOWN) { - handled = TRUE; + make_ui_sound("UISndClick"); + } + if (!handled && mClickedCallback) + { // Route future Mouse messages here preemptively. (Release on mouse up.) gFocusMgr.setMouseCapture( this ); - - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } - } - if (!handled) - { - handled = LLTextBase::handleMouseDown(x, y, mask); + handled = TRUE; } return handled; @@ -76,33 +69,30 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; - // We only handle the click if the click both started and ended within us - - // HACK: Only do this if there actually is something to click, so that - // overly large text boxes in the older UI won't start eating clicks. - if (isClickable() && hasMouseCapture()) + if (getSoundFlags() & MOUSE_UP) { - handled = TRUE; + make_ui_sound("UISndClickRelease"); + } + // We only handle the click if the click both started and ended within us + if (hasMouseCapture()) + { // Release the mouse gFocusMgr.setMouseCapture( NULL ); - if (getSoundFlags() & MOUSE_UP) - { - make_ui_sound("UISndClickRelease"); - } - - // handle clicks on Urls in the textbox first - handled = LLTextBase::handleMouseUp(x, y, mask); - - // DO THIS AT THE VERY END to allow the button to be destroyed + // DO THIS AT THE VERY END to allow the button to be destroyed // as a result of being clicked. If mouseup in the widget, // it's been clicked if (mClickedCallback && !handled) { mClickedCallback(); + handled = TRUE; } } + else + { + handled = LLTextBase::handleMouseUp(x, y, mask); + } return handled; } @@ -149,30 +139,3 @@ void LLTextBox::onUrlLabelUpdated(const std::string &url, const std::string &lab needsReflow(); } -bool LLTextBox::isClickable() const -{ - // return true if we have been given a click callback - if (mClickedCallback) - { - return true; - } - - // also return true if we have a clickable Url in the text - segment_set_t::const_iterator it; - for (it = mSegments.begin(); it != mSegments.end(); ++it) - { - LLTextSegmentPtr segmentp = *it; - if (segmentp) - { - const LLStyleSP style = segmentp->getStyle(); - if (style && style->isLink()) - { - return true; - } - } - } - - // otherwise there is nothing clickable here - return false; -} - diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index f8c4447b62..da0bcbe972 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -79,7 +79,6 @@ public: protected: void onUrlLabelUpdated(const std::string &url, const std::string &label); - bool isClickable() const; LLUIString mText; callback_t mClickedCallback; -- cgit v1.2.3 From 14d06ebe953da7e50b5c9086eee3f048578438ba Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Tue, 6 Oct 2009 01:25:47 +0000 Subject: made "more" link in LLExpandableTextBox localizable fixed logic for showing/hiding "more" link in LLExpandableTextBox fixed invisible background on combobox popup list reviewed by Leyla --- indra/llui/lltextbase.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 62f03f47e6..3dacf979c7 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -807,6 +807,9 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) ++cur_seg_iter; } } + + // layout potentially changed + needsReflow(); } BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) -- cgit v1.2.3 From ebdbdc42f801bc26f3f80252d7ea36e9bfd29d51 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Tue, 6 Oct 2009 20:03:04 +0000 Subject: EXT-1013 - tab ordering is inconsistent in the preferences window reviewed by James --- indra/llui/llpanel.cpp | 2 +- indra/llui/lluictrlfactory.cpp | 8 -------- indra/llui/lluictrlfactory.h | 7 ++----- 3 files changed, 3 insertions(+), 14 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 1695aee2b8..69ff3dddc3 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -522,7 +522,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu // be built/added. JC if (parent) { - S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1; + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup(); parent->addChild(this, tab_group); } diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 4ce6677294..d8633453a8 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -379,14 +379,6 @@ BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& na return res; } -//static -void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group) -{ - if (tab_group < 0) tab_group = parent->getLastTabGroup(); - parent->addChild(view, tab_group); -} - - // Avoid directly using LLUI and LLDir in the template code //static std::string LLUICtrlFactory::findSkinnedFilename(const std::string& filename) diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index e47010c316..5a028702e7 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -295,8 +295,8 @@ fail: if (parent) { - S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1; - setCtrlParent(widget, parent, tab_group); + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup(); + parent->addChild(widget, tab_group); } typedef typename T::child_registry_t registry_t; @@ -321,9 +321,6 @@ fail: static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); private: - //static void setCtrlValue(LLView* view, LLXMLNodePtr node); - static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group); - // Avoid directly using LLUI and LLDir in the template code static std::string findSkinnedFilename(const std::string& filename); -- cgit v1.2.3 From 29ca0f064d56d957839aa05d94786b0c2d5ad5e5 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Tue, 6 Oct 2009 21:09:54 +0000 Subject: fix for gcc --- indra/llui/lluictrlfactory.cpp | 8 ++++++++ indra/llui/lluictrlfactory.h | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index d8633453a8..4ce6677294 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -379,6 +379,14 @@ BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& na return res; } +//static +void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group) +{ + if (tab_group < 0) tab_group = parent->getLastTabGroup(); + parent->addChild(view, tab_group); +} + + // Avoid directly using LLUI and LLDir in the template code //static std::string LLUICtrlFactory::findSkinnedFilename(const std::string& filename) diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 5a028702e7..3c77c655b8 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -295,8 +295,8 @@ fail: if (parent) { - S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup(); - parent->addChild(widget, tab_group); + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1; + setCtrlParent(widget, parent, tab_group); } typedef typename T::child_registry_t registry_t; @@ -321,6 +321,9 @@ fail: static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); private: + // this exists to get around dependency on llview + static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group); + // Avoid directly using LLUI and LLDir in the template code static std::string findSkinnedFilename(const std::string& filename); -- cgit v1.2.3 From 8086923d663cbca32a9b147973f912adcbd4a08a Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Tue, 6 Oct 2009 22:55:01 +0000 Subject: EXT-1283 [Inspectors] Avatar gear menu does not dismiss when selecting another AV reviewed by James --- indra/llui/llmenubutton.cpp | 6 ++++++ indra/llui/llmenubutton.h | 1 + indra/llui/lltooltip.cpp | 12 +++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 2bb6749c83..8dbcd6e229 100644 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -83,6 +83,12 @@ void LLMenuButton::toggleMenu() } +void LLMenuButton::hideMenu() +{ + mMenu->setVisible(FALSE); +} + + BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask ) { if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key)) diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index 94b0e4355d..02eb9d3806 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -54,6 +54,7 @@ public: /*virtual*/ void draw(); /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); + void hideMenu(); protected: friend class LLUICtrlFactory; diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index d742281f30..c55273cacf 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -38,6 +38,7 @@ // Library includes #include "lltextbox.h" #include "lliconctrl.h" +#include "llmenugl.h" // hideMenus() #include "llui.h" // positionViewNearMouse() #include "llwindow.h" @@ -94,7 +95,16 @@ BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolTipView::handleMouseDown(S32 x, S32 y, MASK mask) { LLToolTipMgr::instance().blockToolTips(); - return LLView::handleMouseDown(x, y, mask); + + if (LLView::handleMouseDown(x, y, mask)) + { + // If we are handling the mouse event menu holder + // won't get a chance to close menus so do this here + LLMenuGL::sMenuContainer->hideMenus(); + return TRUE; + } + + return FALSE; } BOOL LLToolTipView::handleMiddleMouseDown(S32 x, S32 y, MASK mask) -- cgit v1.2.3 From ae0827d387dc1e4d0f8a749cab36138f8ac174a0 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Wed, 7 Oct 2009 07:09:34 +0000 Subject: merge https://svn.aws.productengine.com/secondlife/export-from-ll/viewer-2-0@1908 https://svn.aws.productengine.com/secondlife/pe/stable-2@1917 -> viewer-2.0.0-3 * Bugs: EXT-1257 EXT-1299 EXT-1149 EXT-1117 EXT-1134 * New Dev: EXT-721 --- indra/llui/lldockablefloater.cpp | 10 ++++++++++ indra/llui/lldockablefloater.h | 3 +++ indra/llui/lldockcontrol.cpp | 22 +++++++++++++++++++--- 3 files changed, 32 insertions(+), 3 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 4525f0a45b..c512ef25be 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -91,6 +91,16 @@ void LLDockableFloater::setVisible(BOOL visible) LLFloater::setVisible(visible); } +void LLDockableFloater::onDockHidden() +{ + setCanDock(FALSE); +} + +void LLDockableFloater::onDockShown() +{ + setCanDock(TRUE); +} + void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) { if (mDockControl.get() != NULL && mDockControl.get()->isDockVisible()) diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index ed90567ad3..7d91d007ee 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -68,6 +68,9 @@ public: */ /*virtual*/ void setVisible(BOOL visible); + virtual void onDockHidden(); + virtual void onDockShown(); + private: /** * Provides unique of dockable floater. diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index 146c7a969a..cdcd823b1c 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -33,6 +33,7 @@ #include "linden_common.h" #include "lldockcontrol.h" +#include "lldockablefloater.h" LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) : @@ -91,8 +92,8 @@ void LLDockControl::repositionDockable() // recalculate dockable position if dock position changed, dock visibility changed, // root view rect changed or recalculation is forced - if (mEnabled && (mPrevDockRect != dockRect || prev_visibility != mDockWidget->getVisible() - || mRootRect != rootRect || mRecalculateDocablePosition)) + if (mPrevDockRect != dockRect || prev_visibility != mDockWidget->getVisible() + || mRootRect != rootRect || mRecalculateDocablePosition) { // undock dockable and off() if dock not visible if (!isDockVisible()) @@ -100,10 +101,25 @@ void LLDockControl::repositionDockable() mDockableFloater->setDocked(false); // force off() since dockable may not have dockControll at this time off(); + LLDockableFloater* dockable_floater = + dynamic_cast (mDockableFloater); + if(dockable_floater != NULL) + { + dockable_floater->onDockHidden(); + } } else { - moveDockable(); + if(mEnabled) + { + moveDockable(); + } + LLDockableFloater* dockable_floater = + dynamic_cast (mDockableFloater); + if(dockable_floater != NULL) + { + dockable_floater->onDockShown(); + } } mPrevDockRect = dockRect; -- cgit v1.2.3 From ec84b639ed71c1dac8457867148d8aea6d595685 Mon Sep 17 00:00:00 2001 From: James Cook Date: Wed, 7 Oct 2009 20:54:31 +0000 Subject: EXT-1339 Create onClose method in LLFloater, and remove most bindings to mCloseSignal. In the vast majority of cases, mCloseSignal is being bound to an onClose function. Just make it virtual and be done with it. Renamed a couple of LLPanel close methods to onClosePanel() to distinguish them. Reviewed with Richard. --- indra/llui/llfloater.cpp | 3 ++- indra/llui/llfloater.h | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 564e4d748f..b7a15a2b33 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -664,7 +664,8 @@ void LLFloater::closeFloater(bool app_quitting) dirtyRect(); - // Close callback + // Close callbacks + onClose(app_quitting); mCloseSignal(this, LLSD(app_quitting)); // Hide or Destroy diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 1dc5177f81..17ffc94014 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -208,8 +208,8 @@ public: virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); virtual void draw(); - // *TODO: Eliminate this in favor of mOpenSignal virtual void onOpen(const LLSD& key) {} + virtual void onClose(bool app_quitting) {} // This cannot be "const" until all derived floater canClose() // methods are const as well. JC @@ -293,11 +293,18 @@ private: void addResizeCtrls(); void addDragHandle(); +public: + // Called when floater is opened, passes mKey + // Public so external views or floaters can watch for this floater opening + commit_signal_t mOpenSignal; + + // Called when floater is closed, passes app_qitting as LLSD() + // Public so external views or floaters can watch for this floater closing + commit_signal_t mCloseSignal; + protected: std::string mRectControl; std::string mVisibilityControl; - commit_signal_t mOpenSignal; // Called when floater is opened, passes mKey - commit_signal_t mCloseSignal; // Called when floater is closed, passes app_qitting as LLSD() LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg LLDragHandle* mDragHandle; -- cgit v1.2.3