diff options
author | Richard Nelson <richard@lindenlab.com> | 2009-10-20 00:41:41 +0000 |
---|---|---|
committer | Richard Nelson <richard@lindenlab.com> | 2009-10-20 00:41:41 +0000 |
commit | ce5a5f84d5b5aee95b0b130d0fbdb8fbaa688ba7 (patch) | |
tree | b710655439feee3af795dd3311edd4bbf93d5568 | |
parent | b36eee458126f191022c4483d3a496cbbf7dc30c (diff) |
ext-1670 - fix the chat history use of widgets
reviewed by leyla
-rw-r--r-- | indra/llui/lltextbase.cpp | 125 | ||||
-rw-r--r-- | indra/llui/lltextbase.h | 14 | ||||
-rw-r--r-- | indra/llui/lltexteditor.cpp | 14 | ||||
-rw-r--r-- | indra/llui/lltexteditor.h | 2 | ||||
-rw-r--r-- | indra/newview/llchathistory.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llexpandabletextbox.cpp | 17 | ||||
-rw-r--r-- | indra/newview/llexpandabletextbox.h | 2 | ||||
-rw-r--r-- | indra/newview/llviewertexteditor.cpp | 12 |
8 files changed, 100 insertions, 88 deletions
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 4cf8d76827..1d36a16ea7 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -340,11 +340,14 @@ void LLTextBase::drawSelectionBackground() S32 segment_line_start = segmentp->getStart() + segment_offset; S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd); + S32 segment_width, segment_height; + // if selection after beginning of segment if(selection_left >= segment_line_start) { S32 num_chars = llmin(selection_left, segment_line_end) - segment_line_start; - selection_rect.mLeft += segmentp->getWidth(segment_offset, num_chars); + segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height); + selection_rect.mLeft += segment_width; } // if selection spans end of current segment... @@ -352,13 +355,16 @@ void LLTextBase::drawSelectionBackground() { // extend selection slightly beyond end of line // to indicate selection of newline character (use "n" character to determine width) - selection_rect.mRight += segmentp->getWidth(segment_offset, segment_line_end - segment_line_start); + S32 num_chars = segment_line_end - segment_line_start; + segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height); + selection_rect.mRight += segment_width; } // else if selection ends on current segment... else { S32 num_chars = selection_right - segment_line_start; - selection_rect.mRight += segmentp->getWidth(segment_offset, num_chars); + segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height); + selection_rect.mRight += segment_width; break; } @@ -424,7 +430,9 @@ void LLTextBase::drawCursor() if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) { - S32 width = llmax(CURSOR_THICKNESS, segmentp->getWidth(mCursorPos - segmentp->getStart(), 1)); + S32 segment_width, segment_height; + segmentp->getDimensions(mCursorPos - segmentp->getStart(), 1, segment_width, segment_height); + S32 width = llmax(CURSOR_THICKNESS, segment_width); cursor_rect.mRight = cursor_rect.mLeft + width; } else @@ -1087,24 +1095,18 @@ void LLTextBase::reflow(S32 start_index) 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); - + S32_MAX); - S32 segment_width = segment->getWidth(seg_offset, character_count); + S32 segment_width, segment_height; + segment->getDimensions(seg_offset, character_count, segment_width, segment_height); + // grow line height as necessary based on reported height of this segment + line_height = llmax(line_height, segment_height); remaining_pixels -= segment_width; seg_offset += character_count; @@ -1120,16 +1122,6 @@ void LLTextBase::reflow(S32 start_index) // 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++; - } - // add line info and keep going mLineInfoList.push_back(line_info( line_start_index, @@ -1141,7 +1133,6 @@ void LLTextBase::reflow(S32 start_index) 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()) @@ -1801,7 +1792,8 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round S32 segment_line_start = segmentp->getStart() + line_seg_offset; S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd - 1) - segment_line_start; - S32 text_width = segmentp->getWidth(line_seg_offset, segment_line_length); + S32 text_width, text_height; + segmentp->getDimensions(line_seg_offset, segment_line_length, text_width, text_height); if (local_x < start_x + text_width // cursor to left of right edge of text || segmentp->getEnd() >= line_iter->mDocIndexEnd - 1) // or this segment wraps to next line { @@ -1809,7 +1801,8 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round S32 offset; if (!segmentp->canEdit()) { - S32 segment_width = segmentp->getWidth(0, segmentp->getEnd() - segmentp->getStart()); + S32 segment_width, segment_height; + segmentp->getDimensions(0, segmentp->getEnd() - segmentp->getStart(), segment_width, segment_height); if (round && local_x - start_x > segment_width / 2) { offset = segment_line_length; @@ -1868,14 +1861,18 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const if (line_seg_iter == cursor_seg_iter) { // cursor advanced to right based on difference in offset of cursor to start of line - local_rect.mLeft += segmentp->getWidth(line_seg_offset, cursor_seg_offset - line_seg_offset); + S32 segment_width, segment_height; + segmentp->getDimensions(line_seg_offset, cursor_seg_offset - line_seg_offset, segment_width, segment_height); + local_rect.mLeft += segment_width; break; } else { // add remainder of current text segment to cursor position - local_rect.mLeft += segmentp->getWidth(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset); + S32 segment_width, segment_height; + segmentp->getDimensions(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset, segment_width, segment_height); + local_rect.mLeft += segment_width; // offset will be 0 for all segments after the first line_seg_offset = 0; // go to next text segment on this line @@ -2115,12 +2112,11 @@ LLRect LLTextBase::getVisibleDocumentRect() const LLTextSegment::~LLTextSegment() {} -S32 LLTextSegment::getWidth(S32 first_char, S32 num_chars) const { return 0; } +void LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { width = 0; height = 0; } S32 LLTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { return 0; } S32 LLTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const { return 0; } void LLTextSegment::updateLayout(const LLTextBase& editor) {} F32 LLTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) { return draw_rect.mLeft; } -S32 LLTextSegment::getMaxHeight() const { return 0; } bool LLTextSegment::canEdit() const { return false; } void LLTextSegment::unlinkFromDocument(LLTextBase*) {} void LLTextSegment::linkToDocument(LLTextBase*) {} @@ -2158,7 +2154,7 @@ LLNormalTextSegment::LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 mToken(NULL), mEditor(editor) { - mMaxHeight = llceil(mStyle->getFont()->getLineHeight()); + mFontHeight = llceil(mStyle->getFont()->getLineHeight()); } LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) @@ -2168,7 +2164,7 @@ LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 { mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color)); - mMaxHeight = llceil(mStyle->getFont()->getLineHeight()); + mFontHeight = llceil(mStyle->getFont()->getLineHeight()); } F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) @@ -2266,11 +2262,6 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele return right_x; } -S32 LLNormalTextSegment::getMaxHeight() const -{ - return mMaxHeight; -} - BOOL LLNormalTextSegment::handleHover(S32 x, S32 y, MASK mask) { if (getStyle() && getStyle()->isLink()) @@ -2344,10 +2335,21 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip) mTooltip = tooltip; } -S32 LLNormalTextSegment::getWidth(S32 first_char, S32 num_chars) const +void LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { LLWString text = mEditor.getWText(); - return mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); + + // look for any printable character, then return the font height + height = 0; + for (S32 index = mStart + first_char; index < mStart + first_char + num_chars; ++index) + { + if (text[index] != '\n') + { + height = mFontHeight; + break; + } + } + width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); } S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const @@ -2363,6 +2365,17 @@ S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const { LLWString text = mEditor.getWText(); + + // search for newline and if found, truncate there + S32 last_char = mStart + segment_offset; + for (; last_char != mEnd; ++last_char) + { + if (text[last_char] == '\n') break; + } + + // set max characters to length of segment, or to first newline + max_chars = llmin(max_chars, last_char - (mStart + segment_offset)); + S32 num_chars = mStyle->getFont()->maxDrawableChars(text.c_str() + segment_offset + mStart, (F32)num_pixels, max_chars, @@ -2380,6 +2393,10 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin // include terminating NULL num_chars++; } + else if (text[mStart + segment_offset + num_chars] == '\n') + { + num_chars++; + } return num_chars; } @@ -2399,9 +2416,10 @@ void LLNormalTextSegment::dump() const // LLInlineViewSegment // -LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end) +LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end, bool force_new_line) : LLTextSegment(start, end), - mView(view) + mView(view), + mForceNewLine(force_new_line) { } @@ -2410,21 +2428,29 @@ LLInlineViewSegment::~LLInlineViewSegment() mView->die(); } -S32 LLInlineViewSegment::getWidth(S32 first_char, S32 num_chars) const +void LLInlineViewSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { if (first_char == 0 && num_chars == 0) { - return 0; + // we didn't fit on a line, the widget will fall on the next line + // so dimensions here are 0 + width = 0; + height = 0; } else { - return mView->getRect().getWidth(); + width = mView->getRect().getWidth(); + height = mView->getRect().getHeight(); } } S32 LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const { - if (line_offset != 0 && num_pixels < mView->getRect().getWidth()) + // if putting a widget anywhere but at the beginning of a line + // and the widget doesn't fit or mForceNewLine is true + // then return 0 chars for that line, and all characters for the next + if (line_offset != 0 + && (mForceNewLine || num_pixels < mView->getRect().getWidth())) { return 0; } @@ -2446,11 +2472,6 @@ F32 LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selec return (F32)(draw_rect.mLeft + mView->getRect().getWidth()); } -S32 LLInlineViewSegment::getMaxHeight() const -{ - return mView->getRect().getHeight(); -} - void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor) { editor->removeDocumentChild(mView); diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index ca9b1cc123..c05a31baec 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -366,12 +366,11 @@ public: LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){}; virtual ~LLTextSegment(); - virtual S32 getWidth(S32 first_char, S32 num_chars) const; + virtual void getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; virtual S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; virtual void updateLayout(const class LLTextBase& editor); virtual F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); - virtual S32 getMaxHeight() const; virtual bool canEdit() const; virtual void unlinkFromDocument(class LLTextBase* editor); virtual void linkToDocument(class LLTextBase* editor); @@ -418,11 +417,10 @@ public: LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextBase& editor ); LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); - /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const; + /*virtual*/ void getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); - /*virtual*/ S32 getMaxHeight() const; /*virtual*/ bool canEdit() const { return true; } /*virtual*/ const LLColor4& getColor() const { return mStyle->getColor(); } /*virtual*/ void setColor(const LLColor4 &color) { mStyle->setColor(color); } @@ -446,7 +444,7 @@ protected: protected: class LLTextBase& mEditor; LLStyleSP mStyle; - S32 mMaxHeight; + S32 mFontHeight; LLKeywordToken* mToken; std::string mTooltip; }; @@ -460,19 +458,19 @@ public: class LLInlineViewSegment : public LLTextSegment { public: - LLInlineViewSegment(LLView* widget, S32 start, S32 end); + LLInlineViewSegment(LLView* widget, S32 start, S32 end, bool force_new_line); ~LLInlineViewSegment(); - /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const; + /*virtual*/ void getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; /*virtual*/ void updateLayout(const class LLTextBase& editor); /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); - /*virtuaL*/ S32 getMaxHeight() const; /*virtual*/ bool canEdit() const { return false; } /*virtual*/ void unlinkFromDocument(class LLTextBase* editor); /*virtual*/ void linkToDocument(class LLTextBase* editor); private: LLView* mView; + bool mForceNewLine; }; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 7c925b8899..953c5b292f 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2276,7 +2276,7 @@ void LLTextEditor::insertText(const std::string &new_text) setEnabled( enabled ); } -void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool prepend_newline) +void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool force_new_line) { // Save old state S32 selection_start = mSelectionStart; @@ -2293,17 +2293,9 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, LLWString widget_wide_text; // Add carriage return if not first line - if (getLength() != 0 - && prepend_newline) - { - widget_wide_text = utf8str_to_wstring(std::string("\n") + widget_text); - } - else - { - widget_wide_text = utf8str_to_wstring(widget_text); - } + widget_wide_text = utf8str_to_wstring(widget_text); - LLTextSegmentPtr segment = new LLInlineViewSegment(widget, old_length, old_length + widget_text.size()); + LLTextSegmentPtr segment = new LLInlineViewSegment(widget, old_length, old_length + widget_text.size(), force_new_line); insert(getLength(), widget_wide_text, FALSE, segment); needsReflow(); diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index e232efbfb3..82f3956855 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -165,7 +165,7 @@ public: // inserts text at cursor void insertText(const std::string &text); - void appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool prepend_newline); + void appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool force_newline); // Non-undoable void setText(const LLStringExplicit &utf8str); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 80f3867a80..cc21b636f1 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -109,7 +109,7 @@ void LLChatHistory::appendWidgetMessage(const LLUUID& avatar_id, std::string& fr view_text = from + MESSAGE_USERNAME_DATE_SEPARATOR + time; } //Prepare the rect for the view - LLRect target_rect = mScroller->getContentWindowRect(); + LLRect target_rect = getDocumentView()->getRect(); target_rect.mLeft += mLeftWidgetPad; target_rect.mRight -= mRightWidgetPad; view->reshape(target_rect.getWidth(), view->getRect().getHeight()); diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index e2d6bcee8f..48b5fc11b7 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -48,10 +48,11 @@ public: mExpanderLabel(more_text) {} - /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const + /*virtual*/ void getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { // more label always spans width of text box - return mEditor.getTextRect().getWidth(); + width = mEditor.getTextRect().getWidth(); + height = llceil(mStyle->getFont()->getLineHeight()); } /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { @@ -85,8 +86,9 @@ public: mEditor.getUseEllipses()); return right_x; } - /*virtual*/ S32 getMaxHeight() const { return llceil(mStyle->getFont()->getLineHeight()); } /*virtual*/ bool canEdit() const { return false; } + // eat handleMouseDown event so we get the mouseup event + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return TRUE; } /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) { mEditor.onCommit(); return TRUE; } /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) { @@ -126,9 +128,12 @@ void LLExpandableTextBox::LLTextBoxEx::reshape(S32 width, S32 height, BOOL calle } } -void LLExpandableTextBox::LLTextBoxEx::setValue(const LLSD& value) +void LLExpandableTextBox::LLTextBoxEx::setText(const LLStringExplicit& text) { - LLTextBox::setValue(value); + // LLTextBox::setText will obliterate the expander segment, so make sure + // we generate it again by clearing mExpanderVisible + mExpanderVisible = false; + LLTextBox::setText(text); // text contents have changed, segments are cleared out // so hide the expander and determine if we need it @@ -395,7 +400,6 @@ void LLExpandableTextBox::onTopLost() void LLExpandableTextBox::setValue(const LLSD& value) { collapseTextBox(); - mText = value.asString(); mTextBox->setValue(value); } @@ -403,7 +407,6 @@ void LLExpandableTextBox::setValue(const LLSD& value) void LLExpandableTextBox::setText(const std::string& str) { collapseTextBox(); - mText = str; mTextBox->setText(str); } diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h index d6401e224f..d45527aabb 100644 --- a/indra/newview/llexpandabletextbox.h +++ b/indra/newview/llexpandabletextbox.h @@ -60,7 +60,7 @@ protected: // adds or removes "More" link as needed /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ void setText(const LLStringExplicit& text); /** * Returns difference between text box height and text height. diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 0ce1ecc6ee..65994dfb30 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -130,15 +130,17 @@ public: mToolTip = inv_item->getName() + '\n' + inv_item->getDescription(); } - /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const + /*virtual*/ void getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { if (num_chars == 0) { - return 0; + width = 0; + height = 0; } else { - return EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidth(mLabel.c_str()); + width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidth(mLabel.c_str()); + height = llmax(mImage->getHeight(), llceil(mStyle->getFont()->getLineHeight())); } } @@ -169,10 +171,6 @@ public: return right_x; } - /*virtual*/ S32 getMaxHeight() const - { - return llmax(mImage->getHeight(), llceil(mStyle->getFont()->getLineHeight())); - } /*virtual*/ bool canEdit() const { return false; } |