diff options
author | Martin Reddy <lynx@lindenlab.com> | 2009-09-04 12:11:27 +0000 |
---|---|---|
committer | Martin Reddy <lynx@lindenlab.com> | 2009-09-04 12:11:27 +0000 |
commit | 330840af7c363accc8e12d073ba91b871c578d27 (patch) | |
tree | 4539a78e8201ee2508b6d598639efe9a989b6531 /indra/newview/llchatmsgbox.cpp | |
parent | 2273376dffb80af0cbf1bc1d8cc8990e1d1456f3 (diff) |
Merging the SLURLs Everywhere branch (viewer-2.0.0-slurls-3) into
Viewer 2.0 (viewer-2.0.0-3). This provides support for clickable Urls
in text editors and textboxes, with right-click context menus,
tooltips, and alternate link labels. This includes alert boxes, the
login progress window, local chat and IM interfaces, etc. As well as
context menus for avatars and groups in list widgets. Includes fixes
for the following individual JIRAs:
DEV-8763 VWR-10636: Hyperlinks in alert dialogs should be selectable (clickable)!
DEV-38829 EXT-742: Remove LLLink class
DEV-35459 VWR-14679: SLURLs and teleport Links not parsed properly
DEV-19842 VWR-8773: Closing parenthesis ")" breaks urls
DEV-21577 VWR-9405: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat
DEV-37652 SEC-435: Object Chat/IMs are untraceable (VWR-2388) Fix has left flaw
DEV-10353: URLs in chat log terminated incorrectly when newline in chat
DEV-2925: In chat history, use a teleport hyperlink as source name for object IMs
DEV-36192: Need a way to copy Avatar names and Group names
DEV-2926: Allow viewer hyperlinks to have different text than the actual url
DEV-27253: Add easy way to copy URLs from viewer chat
DEV-38274: Make About Second Life window use new Url hyperlinking features
DEV-39076: No url support in Text Editors
DEV-7476 VWR-2172: Add hyperlinks to chat console for easier access
DEV-7475: Add hyperlinks to notecards!
DEV-35375 EXT-128: HTTPS urls aren't loaded in the internal browser by click
Master JIRA issues: DEV-32819, DEV-323820, DEV-7474
Testing performed against QAR-1789
svn merge -r 131623:131889 svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-slurl-3
svn merge -r 131978:132515 svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-slurl-3
Diffstat (limited to 'indra/newview/llchatmsgbox.cpp')
-rw-r--r-- | indra/newview/llchatmsgbox.cpp | 372 |
1 files changed, 54 insertions, 318 deletions
diff --git a/indra/newview/llchatmsgbox.cpp b/indra/newview/llchatmsgbox.cpp index fb5ab8ec5a..e6398dd47a 100644 --- a/indra/newview/llchatmsgbox.cpp +++ b/indra/newview/llchatmsgbox.cpp @@ -1,10 +1,11 @@ /** * @file llchatmsgbox.cpp + * @author Martin Reddy * @brief chat history text box, able to show array of strings with separator * - * $LicenseInfo:firstyear=2004&license=viewergpl$ + * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2004-2009, Linden Research, Inc. + * Copyright (c) 2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -30,361 +31,96 @@ * $/LicenseInfo$ */ - #include "llviewerprecompiledheaders.h" #include "llchatmsgbox.h" #include "llwindow.h" -#include "llfocusmgr.h" - -static LLDefaultChildRegistry::Register<LLChatMsgBox> r("text_chat"); -LLChatMsgBox::Params::Params() -: text_color("text_color"), - highlight_on_hover("hover", false), - border_visible("border_visible", false), - border_drop_shadow_visible("border_drop_shadow_visible", false), - bg_visible("bg_visible", false), - use_ellipses("use_ellipses"), - word_wrap("word_wrap", false), - hover_color("hover_color"), - disabled_color("disabled_color"), - background_color("background_color"), - border_color("border_color"), - line_spacing("line_spacing", 4), - block_spacing("block_spacing",10), - text("text"), - font_shadow("font_shadow", LLFontGL::NO_SHADOW) -{} -LLChatMsgBox::LLChatMsgBox(const LLChatMsgBox::Params& p) -: LLUICtrl(p), - mFontGL(p.font), - mHoverActive( p.highlight_on_hover ), - mHasHover( FALSE ), - mBackgroundVisible( p.bg_visible ), - mBorderVisible( p.border_visible ), - mShadowType( p.font_shadow ), - mBorderDropShadowVisible( p.border_drop_shadow_visible ), - mUseEllipses( p.use_ellipses ), - mVAlign( LLFontGL::TOP ), - mClickedCallback(NULL), - mTextColor(p.text_color()), - mDisabledColor(p.disabled_color()), - mBackgroundColor(p.background_color()), - mBorderColor(p.border_color()), - mHoverColor(p.hover_color()), - mHAlign(p.font_halign), - mLineSpacing(p.line_spacing), - mBlockSpasing(p.block_spacing), - mWordWrap( p.word_wrap ), - mFontStyle(LLFontGL::getStyleFromString(p.font.style)) -{ - setText( p.text() ); -} +static LLDefaultChildRegistry::Register<LLChatMsgBox> r("text_chat"); -BOOL LLChatMsgBox::handleMouseDown(S32 x, S32 y, MASK mask) +LLChatMsgBox::Params::Params() : + block_spacing("block_spacing", 10) { - BOOL handled = FALSE; - - // HACK: Only do this if there actually is a click callback, so that - // overly large text boxes in the older UI won't start eating clicks. - if (mClickedCallback) - { - handled = TRUE; - - // Route future Mouse messages here preemptively. (Release on mouse up.) - gFocusMgr.setMouseCapture( this ); - - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } - } - - return handled; + line_spacing = 4; } -BOOL LLChatMsgBox::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 a click callback, so that - // overly large text boxes in the older UI won't start eating clicks. - if (mClickedCallback - && hasMouseCapture()) - { - handled = TRUE; - - // Release the mouse - gFocusMgr.setMouseCapture( NULL ); - - if (getSoundFlags() & MOUSE_UP) - { - make_ui_sound("UISndClickRelease"); - } - - // 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) - { - mClickedCallback(); - } - } - - return handled; -} +LLChatMsgBox::LLChatMsgBox(const Params& p) : + LLTextBox(p), + mBlockSpacing(p.block_spacing) +{} -BOOL LLChatMsgBox::handleHover(S32 x, S32 y, MASK mask) +void LLChatMsgBox::addText( const LLStringExplicit& text ) { - BOOL handled = LLView::handleHover(x,y,mask); - if(mHoverActive) + LLWString t = mText.getWString(); + if (! t.empty()) { - mHasHover = TRUE; // This should be set every frame during a hover. - getWindow()->setCursor(UI_CURSOR_ARROW); + t += '\n'; } - - return (handled || mHasHover); -} - -void LLChatMsgBox::addText( const LLStringExplicit& text ) -{ - boost::shared_ptr<text_block> t(new text_block()); - t->text = wrapText(text); - setLineLengths(*t); - mTextStrings.push_back(t); + t += getWrappedText(text); + LLTextBox::setText(wstring_to_utf8str(t)); + mSeparatorOffset.push_back(getLength()); } void LLChatMsgBox::setText(const LLStringExplicit& text) { - mTextStrings.clear(); - + mSeparatorOffset.clear(); + mText.clear(); addText(text); - -} - -void LLChatMsgBox::resetLineLengths() -{ - for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); - it!=mTextStrings.end();++it) - { - boost::shared_ptr<text_block> tblock = *it; - setLineLengths(*tblock); - } -} - -void LLChatMsgBox::setLineLengths(text_block& t) -{ - t.lines.clear(); - - std::string::size_type cur = 0; - std::string::size_type len = t.text.length(); - - while (cur < len) - { - std::string::size_type end = t.text.getWString().find('\n', cur); - std::string::size_type runLen; - - if (end == std::string::npos) - { - runLen = len - cur; - cur = len; - } - else - { - runLen = end - cur; - cur = end + 1; // skip the new line character - } - - t.lines.push_back( (S32)runLen ); - } -} - -std::string LLChatMsgBox::wrapText(const LLStringExplicit& in_text, F32 max_width) -{ - if (max_width < 0.0f) - { - max_width = (F32)getRect().getWidth(); - } - - LLWString wtext = utf8str_to_wstring(in_text); - LLWString final_wtext; - - LLWString::size_type cur = 0;; - LLWString::size_type len = wtext.size(); - while (cur < len) - { - LLWString::size_type end = wtext.find('\n', cur); - if (end == LLWString::npos) - { - end = len; - } - - LLWString::size_type runLen = end - cur; - if (runLen > 0) - { - LLWString run(wtext, cur, runLen); - LLWString::size_type useLen = - mFontGL->maxDrawableChars(run.c_str(), max_width, runLen, TRUE); - - final_wtext.append(wtext, cur, useLen); - cur += useLen; - // not enough room to add any more characters - if (useLen == 0) break; - } - - if (cur < len) - { - if (wtext[cur] == '\n') - cur += 1; - - // There is no need to to cut line ending symbols found in origin string, see EXT-702. - final_wtext += '\n'; - } - } - - std::string final_text = wstring_to_utf8str(final_wtext); - return final_text; } -S32 LLChatMsgBox::getTextLinesNum() -{ - S32 num_lines = 0; - for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); - it!=mTextStrings.end();++it) - { - boost::shared_ptr<text_block> tblock = *it; - num_lines+=tblock->lines.size(); - } - - if( num_lines < 1 ) - { - num_lines = 1; - } - - return num_lines; +void LLChatMsgBox::setValue(const LLSD& value ) +{ + setText(value.asString()); } S32 LLChatMsgBox::getTextPixelHeight() { + S32 num_blocks = mSeparatorOffset.size(); S32 num_lines = getTextLinesNum(); - return (S32)(num_lines * mFontGL->getLineHeight() + (num_lines-1)*mLineSpacing + mBlockSpasing*(mTextStrings.size()-1) + 2*mLineSpacing);//some extra space -} - -void LLChatMsgBox::setValue(const LLSD& value ) -{ - setText(value.asString()); + return (S32)(num_lines * mDefaultFont->getLineHeight() + \ + (num_lines-1) * mLineSpacing + \ + (num_blocks-1) * mBlockSpacing + \ + 2 * mLineSpacing); } - -void LLChatMsgBox::draw() +S32 LLChatMsgBox::getTextLinesNum() { - if (mBorderVisible) - { - gl_rect_2d_offset_local(getLocalRect(), 2, FALSE); - } - - if( mBorderDropShadowVisible ) - { - static LLUICachedControl<LLColor4> color_drop_shadow ("ColorDropShadow", *(new LLColor4)); - static LLUICachedControl<S32> drop_shadow_tooltip ("DropShadowTooltip", 0); - gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, - color_drop_shadow, drop_shadow_tooltip); - } - - if (mBackgroundVisible) - { - LLRect r( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - gl_rect_2d( r, mBackgroundColor.get() ); - } - - S32 text_x = 0; - switch( mHAlign ) - { - case LLFontGL::LEFT: - break; - case LLFontGL::HCENTER: - text_x = getRect().getWidth() / 2; - break; - case LLFontGL::RIGHT: - text_x = getRect().getWidth() ; - break; - } - - S32 text_y = getRect().getHeight() ; - - if ( getEnabled() ) - { - if(mHasHover) - { - drawText( text_x, text_y, mHoverColor.get() ); - } - else - { - drawText( text_x, text_y, mTextColor.get() ); - } - } - else - { - drawText( text_x, text_y, mDisabledColor.get() ); - } - - if (sDebugRects) + S32 num_lines = getLineCount(); + if (num_lines < 1) { - drawDebugRect(); + num_lines = 1; } - - //// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview) - //std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); - //if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights)) - //{ - // drawDebugRect(); - //} - - mHasHover = FALSE; // This is reset every frame. -} - -void LLChatMsgBox::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - // reparse line lengths - LLView::reshape(width, height, called_from_parent); - resetLineLengths(); + + return num_lines; } -void LLChatMsgBox::drawText( S32 x, S32 y, const LLColor4& color ) +void LLChatMsgBox::drawText(S32 x, S32 y, const LLWString &text, const LLColor4 &color) { + S32 start = 0; S32 width = getRect().getWidth()-10; - - for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); - it!=mTextStrings.end();++it) + // iterate through each block of text that has been added + y -= mLineSpacing; + for (std::vector<S32>::iterator it = mSeparatorOffset.begin(); true ;) { - boost::shared_ptr<text_block> tblock = *it; + // display the text for this block + S32 num_chars = *it - start; + LLWString text = mDisplayText.substr(start, num_chars); + LLTextBox::drawText(x, y, text, color); - S32 cur_pos = 0; - for (std::vector<S32>::iterator iter = tblock->lines.begin(); - iter != tblock->lines.end(); ++iter) + // exit the loop if this is the last text block + start += num_chars + 1; // skip the newline + if (++it == mSeparatorOffset.end()) { - S32 line_length = *iter; - mFontGL->render(tblock->text, cur_pos, (F32)x, (F32)y, color, - mHAlign, mVAlign, - mFontStyle, - mShadowType, - line_length, getRect().getWidth(), NULL, mUseEllipses ); - cur_pos += line_length + 1; - y -= llfloor(mFontGL->getLineHeight()) + mLineSpacing; - - } - std::vector< boost::shared_ptr<text_block> >::iterator next = it; - ++next; - if(next == mTextStrings.end()) break; - //separator - gl_line_2d(5,y-mBlockSpasing/2,width,y-mBlockSpasing/2,LLColor4::grey); - y-=mBlockSpasing; - } + } + // output a separator line between blocks + S32 num_lines = std::count(text.begin(), text.end(), '\n') + 1; + y -= num_lines * (llfloor(mDefaultFont->getLineHeight()) + mLineSpacing); + S32 sep_y = y - mBlockSpacing/2 + mLineSpacing/2; + gl_line_2d(5, sep_y, width, sep_y, LLColor4::grey); + y -= mBlockSpacing; + } } - |