diff options
Diffstat (limited to 'indra/llui')
-rw-r--r-- | indra/llui/llaccordionctrl.cpp | 36 | ||||
-rw-r--r-- | indra/llui/llaccordionctrl.h | 3 | ||||
-rw-r--r-- | indra/llui/llaccordionctrltab.cpp | 39 | ||||
-rw-r--r-- | indra/llui/llaccordionctrltab.h | 1 | ||||
-rw-r--r-- | indra/llui/llcheckboxctrl.cpp | 30 | ||||
-rw-r--r-- | indra/llui/lldockablefloater.cpp | 2 | ||||
-rw-r--r-- | indra/llui/llflatlistview.cpp | 21 | ||||
-rw-r--r-- | indra/llui/llfloater.cpp | 8 | ||||
-rw-r--r-- | indra/llui/llfloater.h | 2 | ||||
-rw-r--r-- | indra/llui/lllocalcliprect.cpp | 42 | ||||
-rw-r--r-- | indra/llui/lllocalcliprect.h | 26 | ||||
-rw-r--r-- | indra/llui/llmenugl.cpp | 15 | ||||
-rw-r--r-- | indra/llui/llmenugl.h | 2 | ||||
-rw-r--r-- | indra/llui/llresmgr.cpp | 4 | ||||
-rw-r--r-- | indra/llui/lltextbase.cpp | 71 | ||||
-rw-r--r-- | indra/llui/lltextbase.h | 19 | ||||
-rw-r--r-- | indra/llui/lltextvalidate.cpp | 18 | ||||
-rw-r--r-- | indra/llui/lltextvalidate.h | 1 | ||||
-rw-r--r-- | indra/llui/llurlentry.cpp | 19 | ||||
-rw-r--r-- | indra/llui/llurlentry.h | 5 | ||||
-rw-r--r-- | indra/llui/llurlmatch.cpp | 6 | ||||
-rw-r--r-- | indra/llui/llurlmatch.h | 6 | ||||
-rw-r--r-- | indra/llui/llurlregistry.cpp | 6 |
23 files changed, 281 insertions, 101 deletions
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 673631f99a..c3ef734823 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -765,6 +765,17 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) } return 0; } + else if(str_action == "deselect_current") + { + // Reset selection to the currently selected tab. + if (mSelectedTab) + { + mSelectedTab->setSelected(false); + mSelectedTab = NULL; + return 1; + } + return 0; + } } else if (info.has("scrollToShowRect")) { @@ -811,6 +822,31 @@ void LLAccordionCtrl::reset () mScrollbar->setDocPos(0); } +void LLAccordionCtrl::expandDefaultTab() +{ + if (mAccordionTabs.size() > 0) + { + LLAccordionCtrlTab* tab = mAccordionTabs.front(); + + if (!tab->getDisplayChildren()) + { + tab->setDisplayChildren(true); + } + + for (size_t i = 1; i < mAccordionTabs.size(); ++i) + { + tab = mAccordionTabs[i]; + + if (tab->getDisplayChildren()) + { + tab->setDisplayChildren(false); + } + } + + arrange(); + } +} + void LLAccordionCtrl::sort() { if (!mTabComparator) diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index b5fdf796cd..f26a380e5f 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -122,6 +122,7 @@ public: S32 notifyParent(const LLSD& info); void reset (); + void expandDefaultTab(); void setComparator(const LLTabComparator* comp) { mTabComparator = comp; } void sort(); @@ -140,6 +141,8 @@ public: const LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; } + bool getFitParent() const {return mFitParent;} + private: void initNoTabsWidget(const LLTextBox::Params& tb_params); void updateNoTabsHelpTextVisibility(); diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 0cccd4e6de..84716394e6 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -33,6 +33,7 @@ #include "linden_common.h" #include "llaccordionctrltab.h" +#include "llaccordionctrl.h" #include "lllocalcliprect.h" #include "llscrollbar.h" @@ -372,9 +373,11 @@ LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p) mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams); addChild(mHeader, 1); - if (mSelectionEnabled) + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLAccordionCtrlTab::selectOnFocusReceived, this)); + + if (!p.selection_enabled) { - LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLAccordionCtrlTab::selectOnFocusReceived, this)); + LLFocusableElement::setFocusLostCallback(boost::bind(&LLAccordionCtrlTab::deselectOnFocusLost, this)); } reshape(100, 200,FALSE); @@ -599,6 +602,15 @@ void LLAccordionCtrlTab::selectOnFocusReceived() getParent()->notifyParent(LLSD().with("action", "select_current")); } +void LLAccordionCtrlTab::deselectOnFocusLost() +{ + if(getParent()) // A parent may not be set if tabs are added dynamically. + { + getParent()->notifyParent(LLSD().with("action", "deselect_current")); + } + +} + S32 LLAccordionCtrlTab::getHeaderHeight() { return mHeaderVisible?HEADER_HEIGHT:0; @@ -699,7 +711,7 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info) setRect(panel_rect); } - //LLAccordionCtrl should rearrange accodion tab if one of accordion change its size + //LLAccordionCtrl should rearrange accordion tab if one of accordion change its size if (getParent()) // A parent may not be set if tabs are added dynamically. getParent()->notifyParent(info); return 1; @@ -710,6 +722,27 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info) return 1; } } + else if (info.has("scrollToShowRect")) + { + LLAccordionCtrl* parent = dynamic_cast<LLAccordionCtrl*>(getParent()); + if (parent && parent->getFitParent()) + { + // EXT-8285 ('No attachments worn' text appears at the bottom of blank 'Attachments' accordion) + // The problem was in passing message "scrollToShowRect" IN LLAccordionCtrlTab::notifyParent + // FROM child LLScrollContainer TO parent LLAccordionCtrl with "it_parent" set to true. + + // It is wrong notification for parent accordion which leads to recursive call of adjustContainerPanel + // As the result of recursive call of adjustContainerPanel we got LLAccordionCtrlTab + // that reshaped and re-sized with different rectangles. + + // LLAccordionCtrl has own scrollContainer and LLAccordionCtrlTab has own scrollContainer + // both should handle own scroll container's event. + // So, if parent accordion "fit_parent" accordion tab should handle its scroll container events itself. + + return 1; + } + } + return LLUICtrl::notifyParent(info); } diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 1344ce0a30..00fb276f19 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -220,6 +220,7 @@ protected: LLView* findContainerView (); void selectOnFocusReceived(); + void deselectOnFocusLost(); private: diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index 3d32157406..0c524cd470 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -81,17 +81,6 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) // must be big enough to hold all children setUseBoundingRect(TRUE); - // Label (add a little space to make sure text actually renders) - const S32 FUDGE = 10; - S32 text_width = mFont->getWidth( p.label ) + FUDGE; - S32 text_height = llround(mFont->getLineHeight()); - LLRect label_rect; - label_rect.setOriginAndSize( - llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, - llcheckboxctrl_vpad + 1, // padding to get better alignment - text_width + llcheckboxctrl_hpad, - text_height ); - // *HACK Get rid of this with SL-55508... // this allows blank check boxes and radio boxes for now std::string local_label = p.label; @@ -101,7 +90,6 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) } LLTextBox::Params tbparams = p.label_text; - tbparams.rect(label_rect); tbparams.initial_value(local_label); if (p.font.isProvided()) { @@ -111,6 +99,17 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams); addChild(mLabel); + S32 text_width = mLabel->getTextBoundingRect().getWidth(); + S32 text_height = llround(mFont->getLineHeight()); + LLRect label_rect; + label_rect.setOriginAndSize( + llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, + llcheckboxctrl_vpad + 1, // padding to get better alignment + text_width + llcheckboxctrl_hpad, + text_height ); + mLabel->setShape(label_rect); + + // Button // Note: button cover the label by extending all the way to the right. LLRect btn_rect; @@ -190,8 +189,7 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); static LLUICachedControl<S32> llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0); - const S32 FUDGE = 10; - S32 text_width = mFont->getWidth( mLabel->getText() ) + FUDGE; + S32 text_width = mLabel->getTextBoundingRect().getWidth(); S32 text_height = llround(mFont->getLineHeight()); LLRect label_rect; label_rect.setOriginAndSize( @@ -199,7 +197,7 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) llcheckboxctrl_vpad, text_width, text_height ); - mLabel->setRect(label_rect); + mLabel->setShape(label_rect); LLRect btn_rect; btn_rect.setOriginAndSize( @@ -207,7 +205,7 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) llcheckboxctrl_vpad, llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width, llmax( text_height, llcheckboxctrl_btn_size() ) ); - mButton->setRect( btn_rect ); + mButton->setShape( btn_rect ); LLUICtrl::reshape(width, height, called_from_parent); } diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 3d8670fef2..4f5fcddbf4 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -49,12 +49,12 @@ void LLDockableFloater::init(LLDockableFloater* thiz) thiz->setCanClose(TRUE); thiz->setCanDock(true); thiz->setCanMinimize(TRUE); + thiz->setOverlapsScreenChannel(false); } LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, const LLSD& key, const Params& params) : LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(true) - , mOverlapsScreenChannel(false) { init(this); mUseTongue = true; diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 90c6f15d23..70558f8eb8 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -615,7 +615,7 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) //only CTRL usage allows to deselect an item, usual clicking on an item cannot deselect it if (mask & MASK_CONTROL) - selectItemPair(item_pair, select_item); + selectItemPair(item_pair, select_item); else selectItemPair(item_pair, true); } @@ -1078,25 +1078,6 @@ void LLFlatListView::setNoItemsCommentVisible(bool visible) const { if (mNoItemsCommentTextbox) { - if (visible) - { -/* -// *NOTE: MA 2010-02-04 -// Deprecated after params of the comment text box were moved into widget (flat_list_view.xml) -// can be removed later if nothing happened. - // We have to update child rect here because of issues with rect after reshaping while creating LLTextbox - // It is possible to have invalid LLRect if Flat List is in LLAccordionTab - LLRect comment_rect = getLocalRect(); - - // To see comment correctly (EXT - 3244) in mNoItemsCommentTextbox we must get border width - // of LLFlatListView (@see getBorderWidth()) and stretch mNoItemsCommentTextbox to this width - // But getBorderWidth() returns 0 if LLFlatListView not visible. So we have to get border width - // from 'scroll_border' - LLViewBorder* scroll_border = getChild<LLViewBorder>("scroll border"); - comment_rect.stretch(-scroll_border->getBorderWidth()); - mNoItemsCommentTextbox->setRect(comment_rect); -*/ - } mSelectedItemsBorder->setVisible(!visible); mNoItemsCommentTextbox->setVisible(visible); } diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 39a6855273..22d6f6ca52 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -451,6 +451,14 @@ void LLFloater::enableResizeCtrls(bool enable) } } +void LLFloater::destroy() +{ + // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before + // it was deleted via LLMortician::updateClass(). See EXT-8458. + LLFloaterReg::removeInstance(mInstanceName, mKey); + die(); +} + // virtual LLFloater::~LLFloater() { diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 3ea035777c..42f422f91c 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -308,7 +308,7 @@ protected: BOOL getAutoFocus() const { return mAutoFocus; } LLDragHandle* getDragHandle() const { return mDragHandle; } - void destroy() { die(); } // Don't call this directly. You probably want to call closeFloater() + void destroy(); // Don't call this directly. You probably want to call closeFloater() virtual void onClickCloseBtn(); diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp index 43c21e250c..55329f64e4 100644 --- a/indra/llui/lllocalcliprect.cpp +++ b/indra/llui/lllocalcliprect.cpp @@ -33,33 +33,8 @@ #include "lllocalcliprect.h" #include "llfontgl.h" -#include "llgl.h" #include "llui.h" -#include <stack> - -//--------------------------------------------------------------------------- -// LLScreenClipRect -// implementation class in screen space -//--------------------------------------------------------------------------- -class LLScreenClipRect -{ -public: - LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE); - virtual ~LLScreenClipRect(); - -private: - static void pushClipRect(const LLRect& rect); - static void popClipRect(); - static void updateScissorRegion(); - -private: - LLGLState mScissorState; - BOOL mEnabled; - - static std::stack<LLRect> sClipRectStack; -}; - /*static*/ std::stack<LLRect> LLScreenClipRect::sClipRectStack; @@ -131,16 +106,11 @@ void LLScreenClipRect::updateScissorRegion() // LLLocalClipRect //--------------------------------------------------------------------------- LLLocalClipRect::LLLocalClipRect(const LLRect& rect, BOOL enabled /* = TRUE */) -{ - LLRect screen(rect.mLeft + LLFontGL::sCurOrigin.mX, - rect.mTop + LLFontGL::sCurOrigin.mY, - rect.mRight + LLFontGL::sCurOrigin.mX, - rect.mBottom + LLFontGL::sCurOrigin.mY); - mScreenClipRect = new LLScreenClipRect(screen, enabled); -} +: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, + rect.mTop + LLFontGL::sCurOrigin.mY, + rect.mRight + LLFontGL::sCurOrigin.mX, + rect.mBottom + LLFontGL::sCurOrigin.mY), enabled) +{} LLLocalClipRect::~LLLocalClipRect() -{ - delete mScreenClipRect; - mScreenClipRect = NULL; -} +{} diff --git a/indra/llui/lllocalcliprect.h b/indra/llui/lllocalcliprect.h index cd0c55ca72..36413f1496 100644 --- a/indra/llui/lllocalcliprect.h +++ b/indra/llui/lllocalcliprect.h @@ -31,7 +31,9 @@ #ifndef LLLOCALCLIPRECT_H #define LLLOCALCLIPRECT_H +#include "llgl.h" #include "llrect.h" // can't forward declare, it's templated +#include <stack> // Clip rendering to a specific rectangle using GL scissor // Just create one of these on the stack: @@ -39,15 +41,29 @@ // LLLocalClipRect(rect); // draw(); // } -class LLLocalClipRect +class LLScreenClipRect { public: - LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE); - ~LLLocalClipRect(); + LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE); + virtual ~LLScreenClipRect(); + +private: + static void pushClipRect(const LLRect& rect); + static void popClipRect(); + static void updateScissorRegion(); private: - // implementation class - class LLScreenClipRect* mScreenClipRect; + LLGLState mScissorState; + BOOL mEnabled; + + static std::stack<LLRect> sClipRectStack; +}; + +class LLLocalClipRect : public LLScreenClipRect +{ +public: + LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE); + ~LLLocalClipRect(); }; #endif diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index b4a1bcb7c5..12007f7b52 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -218,6 +218,12 @@ void LLMenuItemGL::setValue(const LLSD& value) } //virtual +LLSD LLMenuItemGL::getValue() const +{ + return getLabel(); +} + +//virtual BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) { if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) @@ -922,6 +928,15 @@ void LLMenuItemCheckGL::setValue(const LLSD& value) } } +//virtual +LLSD LLMenuItemCheckGL::getValue() const +{ + // Get our boolean value from the view model. + // If we don't override this method then the implementation from + // LLMenuItemGL will return a string. (EXT-8501) + return LLUICtrl::getValue(); +} + // called to rebuild the draw label void LLMenuItemCheckGL::buildDrawLabel( void ) { diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 7668f301ea..bf40163dac 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -95,6 +95,7 @@ public: // LLUICtrl overrides /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ LLSD getValue() const; virtual BOOL handleAcceleratorKey(KEY key, MASK mask); @@ -321,6 +322,7 @@ public: virtual void onCommit( void ); virtual void setValue(const LLSD& value); + virtual LLSD getValue() const; // called to rebuild the draw label virtual void buildDrawLabel( void ); diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index ed870d46d5..9158bc70f5 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -298,11 +298,11 @@ void LLResMgr::getIntegerString( std::string& output, S32 input ) const { if (fraction == remaining_count) { - fraction_string = llformat("%d%c", fraction, getThousandsSeparator()); + fraction_string = llformat_to_utf8("%d%c", fraction, getThousandsSeparator()); } else { - fraction_string = llformat("%3.3d%c", fraction, getThousandsSeparator()); + fraction_string = llformat_to_utf8("%3.3d%c", fraction, getThousandsSeparator()); } output = fraction_string + output; } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 617c496d6a..4bcf7e6980 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1012,21 +1012,26 @@ void LLTextBase::draw() if (mBGVisible) { // clip background rect against extents, if we support scrolling - LLLocalClipRect clip(doc_rect, mScroller != NULL); - + LLRect bg_rect = mVisibleTextRect; + if (mScroller) + { + bg_rect.intersectWith(doc_rect); + } LLColor4 bg_color = mReadOnly ? mReadOnlyBgColor.get() : hasFocus() ? mFocusBgColor.get() : mWriteableBgColor.get(); - gl_rect_2d(mVisibleTextRect, bg_color, TRUE); + gl_rect_2d(doc_rect, bg_color, TRUE); } // draw document view LLUICtrl::draw(); { - // only clip if we support scrolling (mScroller != NULL) + // 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); drawSelectionBackground(); drawText(); @@ -1495,6 +1500,7 @@ LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index) // when there are no segments, we return the end iterator, which must be checked by caller if (mSegments.size() <= 1) { return mSegments.begin(); } + //FIXME: avoid operator new somehow (without running into refcount problems) segment_set_t::iterator it = mSegments.upper_bound(new LLIndexSegment(index)); return it; } @@ -1642,7 +1648,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para } else { - appendAndHighlightText(match.getLabel(), part, link_params); + appendAndHighlightText(match.getLabel(), part, link_params, match.underlineOnHoverOnly()); // set the tooltip for the Url label if (! match.getTooltip().empty()) @@ -1725,7 +1731,7 @@ void LLTextBase::appendWidget(const LLInlineViewSegment::Params& params, const s insertStringNoUndo(getLength(), widget_wide_text, &segments); } -void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params) +void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) { // Save old state S32 selection_start = mSelectionStart; @@ -1756,7 +1762,17 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig S32 cur_length = getLength(); LLStyleConstSP sp(new LLStyle(highlight_params)); - LLTextSegmentPtr segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this); + LLTextSegmentPtr segmentp; + if(underline_on_hover_only) + { + highlight_params.font.style("NORMAL"); + LLStyleConstSP normal_sp(new LLStyle(highlight_params)); + segmentp = new LLOnHoverChangeableTextSegment(sp, normal_sp, cur_length, cur_length + wide_text.size(), *this); + } + else + { + segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this); + } segment_vec_t segments; segments.push_back(segmentp); insertStringNoUndo(cur_length, wide_text, &segments); @@ -1771,7 +1787,17 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig S32 segment_start = old_length; S32 segment_end = old_length + wide_text.size(); LLStyleConstSP sp(new LLStyle(style_params)); + if (underline_on_hover_only) + { + LLStyle::Params normal_style_params(style_params); + normal_style_params.font.style("NORMAL"); + LLStyleConstSP normal_sp(new LLStyle(normal_style_params)); + segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this )); + } + else + { segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this )); + } insertStringNoUndo(getLength(), wide_text, &segments); } @@ -1795,7 +1821,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig } } -void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params) +void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) { if (new_text.empty()) return; @@ -1807,7 +1833,7 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig if(pos!=start) { std::string str = std::string(new_text,start,pos-start); - appendAndHighlightTextImpl(str,highlight_part, style_params); + appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only); } appendLineBreakSegment(style_params); start = pos+1; @@ -1815,7 +1841,7 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig } std::string str = std::string(new_text,start,new_text.length()-start); - appendAndHighlightTextImpl(str,highlight_part, style_params); + appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only); } @@ -2269,6 +2295,7 @@ void LLTextBase::updateRects() // allow horizontal scrolling? // if so, use entire width of text contents // otherwise, stop at width of mVisibleTextRect + //FIXME: consider use of getWordWrap() instead doc_rect.mRight = mScroller ? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight) : mVisibleTextRect.getWidth(); @@ -2675,6 +2702,30 @@ void LLNormalTextSegment::dump() const llendl; } +// +// LLOnHoverChangeableTextSegment +// + +LLOnHoverChangeableTextSegment::LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor ): + LLNormalTextSegment(normal_style, start, end, editor), + mHoveredStyle(style), + mNormalStyle(normal_style){} + +/*virtual*/ +F32 LLOnHoverChangeableTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) +{ + F32 result = LLNormalTextSegment::draw(start, end, selection_start, selection_end, draw_rect); + mStyle = mNormalStyle; + return result; +} + +/*virtual*/ +BOOL LLOnHoverChangeableTextSegment::handleHover(S32 x, S32 y, MASK mask) +{ + mStyle = mHoveredStyle; + return LLNormalTextSegment::handleHover(x, y, mask); +} + // // LLInlineViewSegment diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 86f0e55a1d..4b83d5effb 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -145,6 +145,21 @@ protected: boost::signals2::connection mImageLoadedConnection; }; +// Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment) +class LLOnHoverChangeableTextSegment : public LLNormalTextSegment +{ +public: + LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor ); + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); +protected: + // Style used for text when mouse pointer is over segment + LLStyleConstSP mHoveredStyle; + // Style used for text when mouse pointer is outside segment + LLStyleConstSP mNormalStyle; + +}; + class LLIndexSegment : public LLTextSegment { public: @@ -443,7 +458,7 @@ protected: S32 insertStringNoUndo(S32 pos, const LLWString &wstr, segment_vec_t* segments = NULL); // returns num of chars actually inserted S32 removeStringNoUndo(S32 pos, S32 length); S32 overwriteCharNoUndo(S32 pos, llwchar wc); - void appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& stylep); + void appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& stylep, bool underline_on_hover_only = false); // manage segments @@ -486,7 +501,7 @@ protected: void replaceUrlLabel(const std::string &url, const std::string &label); void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params()); - void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params); + void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false); protected: diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 8b6bc5bd7d..53c4d21151 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -50,6 +50,7 @@ namespace LLTextValidate declare("alpha_num_space", validateAlphaNumSpace); declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe); declare("ascii_printable_no_space", validateASCIIPrintableNoSpace); + declare("ascii_with_newline", validateASCIIWithNewLine); } // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position. @@ -299,4 +300,21 @@ namespace LLTextValidate } return rv; } + + // Used for multiline text stored on the server. + // Example is landmark description in Places SP. + bool validateASCIIWithNewLine(const LLWString &str) + { + bool rv = TRUE; + S32 len = str.length(); + while(len--) + { + if (str[len] < 0x20 && str[len] != 0xA || str[len] > 0x7f) + { + rv = FALSE; + break; + } + } + return rv; + } } diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index ffb4e85e7c..c033f5045b 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -57,6 +57,7 @@ namespace LLTextValidate bool validateASCIIPrintableNoPipe(const LLWString &str); bool validateASCIIPrintableNoSpace(const LLWString &str); bool validateASCII(const LLWString &str); + bool validateASCIIWithNewLine(const LLWString &str); } diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index e075699a6e..17d211fb36 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -363,6 +363,12 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const return LLTrans::getString("TooltipAgentUrl"); } +bool LLUrlEntryAgent::underlineOnHoverOnly(const std::string &string) const +{ + std::string url = getUrl(string); + return LLStringUtil::endsWith(url, "/about"); +} + std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { if (!gCacheName) @@ -730,6 +736,19 @@ std::string LLUrlEntrySLLabel::getTooltip(const std::string &string) const return LLUrlEntryBase::getTooltip(string); } +bool LLUrlEntrySLLabel::underlineOnHoverOnly(const std::string &string) const +{ + std::string url = getUrl(string); + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + return match.underlineOnHoverOnly(); + } + + // unrecognized URL? should not happen + return LLUrlEntryBase::underlineOnHoverOnly(string); +} + // // LLUrlEntryWorldMap Describes secondlife:///<location> URLs // diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 7d718b67a9..f8588dd760 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -94,6 +94,9 @@ public: /// is this a match for a URL that should not be hyperlinked? bool isLinkDisabled() const { return mDisabledLink; } + /// Should this link text be underlined only when mouse is hovered over it? + virtual bool underlineOnHoverOnly(const std::string &string) const { return false; } + virtual LLUUID getID(const std::string &string) const { return LLUUID::null; } protected: @@ -173,6 +176,7 @@ public: /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); /*virtual*/ std::string getTooltip(const std::string &string) const; /*virtual*/ LLUUID getID(const std::string &string) const; + /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; private: void onAgentNameReceived(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); @@ -275,6 +279,7 @@ public: /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); /*virtual*/ std::string getUrl(const std::string &string) const; /*virtual*/ std::string getTooltip(const std::string &string) const; + /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; }; /// diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp index 7c96665ce4..a6d3dcb40f 100644 --- a/indra/llui/llurlmatch.cpp +++ b/indra/llui/llurlmatch.cpp @@ -43,7 +43,8 @@ LLUrlMatch::LLUrlMatch() : mIcon(""), mMenuName(""), mLocation(""), - mDisabledLink(false) + mDisabledLink(false), + mUnderlineOnHoverOnly(false) { } @@ -51,7 +52,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std::string &label, const std::string &tooltip, const std::string &icon, const LLUIColor& color, const std::string &menu, const std::string &location, - bool disabled_link, const LLUUID& id) + bool disabled_link, const LLUUID& id, bool underline_on_hover_only) { mStart = start; mEnd = end; @@ -64,4 +65,5 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, mLocation = location; mDisabledLink = disabled_link; mID = id; + mUnderlineOnHoverOnly = underline_on_hover_only; } diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h index 78dd2c528f..7090dd3f93 100644 --- a/indra/llui/llurlmatch.h +++ b/indra/llui/llurlmatch.h @@ -86,12 +86,15 @@ public: /// is this a match for a URL that should not be hyperlinked? bool isLinkDisabled() const { return mDisabledLink; } + /// Should this link text be underlined only when mouse is hovered over it? + bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; } + /// Change the contents of this match object (used by LLUrlRegistry) void setValues(U32 start, U32 end, const std::string &url, const std::string &label, const std::string &tooltip, const std::string &icon, const LLUIColor& color, const std::string &menu, const std::string &location, bool disabled_link - , const LLUUID& id ); + , const LLUUID& id, bool underline_on_hover_only = false ); const LLUUID& getID() const { return mID;} @@ -108,6 +111,7 @@ private: LLUUID mID; LLUIColor mColor; bool mDisabledLink; + bool mUnderlineOnHoverOnly; }; #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 1f86f72faa..b37a52cad2 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -184,7 +184,8 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL match_entry->getMenuName(), match_entry->getLocation(url), match_entry->isLinkDisabled(), - match_entry->getID(url)); + match_entry->getID(url), + match_entry->underlineOnHoverOnly(url)); return true; } @@ -219,7 +220,8 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr match.getMenuName(), match.getLocation(), match.isLinkDisabled(), - match.getID()); + match.getID(), + match.underlineOnHoverOnly()); return true; } return false; |