diff options
Diffstat (limited to 'indra/llui')
110 files changed, 1941 insertions, 1007 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 5991a5b35e..83b3a220a0 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -18,6 +18,7 @@ set(llui_SOURCE_FILES llbadgeowner.cpp llbutton.cpp llchatentry.cpp + llchatmentionhelper.cpp llcheckboxctrl.cpp llclipboard.cpp llcombobox.cpp @@ -130,6 +131,7 @@ set(llui_HEADER_FILES llcallbackmap.h llchatentry.h llchat.h + llchatmentionhelper.h llcheckboxctrl.h llclipboard.h llcombobox.h diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index cf3569683e..3fdcf9f7f2 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -126,7 +126,7 @@ public: void setSelected(bool is_selected); - bool getCollapsible() { return mCollapsible; }; + bool getCollapsible() const { return mCollapsible; }; void setCollapsible(bool collapsible) { mCollapsible = collapsible; }; void changeOpenClose(bool is_open); @@ -181,7 +181,7 @@ public: void setHeaderVisible(bool value); - bool getHeaderVisible() { return mHeaderVisible;} + bool getHeaderVisible() const { return mHeaderVisible;} S32 mExpandedHeight; // Height of expanded ctrl. // Used to restore height after expand. diff --git a/indra/llui/llbadge.cpp b/indra/llui/llbadge.cpp index de06d56ae0..42b6f1f07b 100644 --- a/indra/llui/llbadge.cpp +++ b/indra/llui/llbadge.cpp @@ -27,6 +27,8 @@ #define LLBADGE_CPP #include "llbadge.h" +#include "llfontgl.h" +#include "llfontvertexbuffer.h" #include "llscrollcontainer.h" #include "lluictrlfactory.h" @@ -202,17 +204,15 @@ void renderBadgeBackground(F32 centerX, F32 centerY, F32 width, F32 height, cons (F32)ll_round(x) + width, (F32)ll_round(y) + height); - LLVector4a vertices[6]; - vertices[0].set(screen_rect.mLeft, screen_rect.mTop, 1.0f); - vertices[1].set(screen_rect.mLeft, screen_rect.mBottom, 1.0f); - vertices[2].set(screen_rect.mRight, screen_rect.mTop, 1.0f); - vertices[3].set(screen_rect.mRight, screen_rect.mTop, 1.0f); - vertices[4].set(screen_rect.mLeft, screen_rect.mBottom, 1.0f); - vertices[5].set(screen_rect.mRight, screen_rect.mBottom, 1.0f); + LLVector4a vertices[4]; + vertices[0].set(screen_rect.mLeft, screen_rect.mTop, 1.0f); + vertices[1].set(screen_rect.mRight, screen_rect.mTop, 1.0f); + vertices[2].set(screen_rect.mLeft, screen_rect.mBottom, 1.0f); + vertices[3].set(screen_rect.mRight, screen_rect.mBottom, 1.0f); - gGL.begin(LLRender::TRIANGLES); + gGL.begin(LLRender::TRIANGLE_STRIP); { - gGL.vertexBatchPreTransformed(vertices, 6); + gGL.vertexBatchPreTransformed(vertices, 4); } gGL.end(); @@ -353,17 +353,17 @@ void LLBadge::draw() // // Draw the label // - - mGLFont->render(mLabel.getWString(), - badge_label_begin_offset, - badge_center_x + mLabelOffsetHoriz, - badge_center_y + mLabelOffsetVert, - mLabelColor % alpha, - LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position - LLFontGL::NORMAL, // normal text (not bold, italics, etc.) - LLFontGL::DROP_SHADOW_SOFT, - badge_char_length, badge_pixel_length, - right_position_out, do_not_use_ellipses); + mFontBuffer.render(mGLFont, + mLabel.getWString(), + badge_label_begin_offset, + badge_center_x + mLabelOffsetHoriz, + badge_center_y + mLabelOffsetVert, + mLabelColor % alpha, + LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position + LLFontGL::NORMAL, // normal text (not bold, italics, etc.) + LLFontGL::DROP_SHADOW_SOFT, + badge_char_length, badge_pixel_length, + right_position_out, do_not_use_ellipses); } } } diff --git a/indra/llui/llbadge.h b/indra/llui/llbadge.h index 77fe76f0da..636e2c9ded 100644 --- a/indra/llui/llbadge.h +++ b/indra/llui/llbadge.h @@ -34,12 +34,14 @@ #include "llstring.h" #include "lluiimage.h" #include "llview.h" +#include "llfontvertexbuffer.h" // // Declarations // class LLFontGL; +class LLFontVertexBuffer; class LLScrollContainer; class LLUICtrlFactory; @@ -144,6 +146,7 @@ private: LLUIColor mBorderColor; const LLFontGL* mGLFont; + LLFontVertexBuffer mFontBuffer; LLPointer< LLUIImage > mImage; LLUIColor mImageColor; diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 30968225a8..d2534b3939 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -43,6 +43,8 @@ #include "llfloater.h" #include "llfloaterreg.h" #include "llfocusmgr.h" +#include "llfontgl.h" +#include "llfontvertexbuffer.h" #include "llwindow.h" #include "llnotificationsutil.h" #include "llrender.h" @@ -120,11 +122,10 @@ LLButton::Params::Params() LLButton::LLButton(const LLButton::Params& p) -: LLUICtrl(p), + : LLUICtrl(p), LLBadgeOwner(getHandle()), mMouseDownFrame(0), mMouseHeldDownCount(0), - mBorderEnabled( false ), mFlashing( false ), mCurGlowStrength(0.f), mNeedsHighlight(false), @@ -329,6 +330,30 @@ void LLButton::onCommit() LLUICtrl::onCommit(); } +void LLButton::setUnselectedLabelColor(const LLUIColor& c) +{ + mUnselectedLabelColor = c; + mFontBuffer.reset(); +} + +void LLButton::setSelectedLabelColor(const LLUIColor& c) +{ + mSelectedLabelColor = c; + mFontBuffer.reset(); +} + +void LLButton::setUseEllipses(bool use_ellipses) +{ + mUseEllipses = use_ellipses; + mFontBuffer.reset(); +} + +void LLButton::setUseFontColor(bool use_font_color) +{ + mUseFontColor = use_font_color; + mFontBuffer.reset(); +} + boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) { return setClickedCallback(initCommitCallback(cb)); @@ -396,6 +421,18 @@ bool LLButton::postBuild() return LLUICtrl::postBuild(); } +void LLButton::onVisibilityChange(bool new_visibility) +{ + mFontBuffer.reset(); + return LLUICtrl::onVisibilityChange(new_visibility); +} + +void LLButton::dirtyRect() +{ + LLUICtrl::dirtyRect(); + mFontBuffer.reset(); +} + bool LLButton::handleUnicodeCharHere(llwchar uni_char) { bool handled = false; @@ -582,19 +619,25 @@ void LLButton::onMouseLeave(S32 x, S32 y, MASK mask) { LLUICtrl::onMouseLeave(x, y, mask); - mNeedsHighlight = false; + setHighlight(false); } void LLButton::setHighlight(bool b) { - mNeedsHighlight = b; + if (mNeedsHighlight != b) + { + mNeedsHighlight = b; + mFontBuffer.reset(); + } } bool LLButton::handleHover(S32 x, S32 y, MASK mask) { if (isInEnabledChain() && (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this)) - mNeedsHighlight = true; + { + setHighlight(true); + } if (!childrenHandleHover(x, y, mask)) { @@ -794,7 +837,7 @@ void LLButton::draw() // Highlight if needed if( ll::ui::SearchableControl::getHighlighted() ) - label_color = ll::ui::SearchableControl::getHighlightColor(); + label_color = ll::ui::SearchableControl::getHighlightFontColor(); // overlay with keyboard focus border if (hasFocus()) @@ -954,7 +997,7 @@ void LLButton::draw() // LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value. // Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode. // Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars. - mLastDrawCharsCount = mGLFont->render(label, 0, + mLastDrawCharsCount = mFontBuffer.render(mGLFont, label, 0, (F32)x, (F32)(getRect().getHeight() / 2 + mBottomVPad), label_color % alpha, @@ -996,6 +1039,7 @@ void LLButton::setToggleState(bool b) setFlashing(false); // stop flash state whenever the selected/unselected state if reset // Unselected label assignments autoResize(); + mFontBuffer.reset(); } } @@ -1025,11 +1069,13 @@ bool LLButton::toggleState() void LLButton::setLabel( const std::string& label ) { mUnselectedLabel = mSelectedLabel = label; + mFontBuffer.reset(); } void LLButton::setLabel( const LLUIString& label ) { mUnselectedLabel = mSelectedLabel = label; + mFontBuffer.reset(); } void LLButton::setLabel( const LLStringExplicit& label ) @@ -1043,17 +1089,32 @@ bool LLButton::setLabelArg( const std::string& key, const LLStringExplicit& text { mUnselectedLabel.setArg(key, text); mSelectedLabel.setArg(key, text); + mFontBuffer.reset(); return true; } void LLButton::setLabelUnselected( const LLStringExplicit& label ) { mUnselectedLabel = label; + mFontBuffer.reset(); } void LLButton::setLabelSelected( const LLStringExplicit& label ) { mSelectedLabel = label; + mFontBuffer.reset(); +} + +void LLButton::setDisabledLabelColor(const LLUIColor& c) +{ + mDisabledLabelColor = c; + mFontBuffer.reset(); +} + +void LLButton::setFont(const LLFontGL* font) +{ + mGLFont = (font ? font : LLFontGL::getFontSansSerif()); + mFontBuffer.reset(); } bool LLButton::labelIsTruncated() const @@ -1066,6 +1127,12 @@ const LLUIString& LLButton::getCurrentLabel() const return getToggleState() ? mSelectedLabel : mUnselectedLabel; } +void LLButton::setDropShadowedText(bool b) +{ + mDropShadowedText = b; + mFontBuffer.reset(); +} + void LLButton::setImageUnselected(LLPointer<LLUIImage> image) { mImageUnselected = image; @@ -1149,6 +1216,7 @@ void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image) mImageDisabledSelected = image; mDisabledImageColor = mImageColor; mFadeWhenDisabled = true; + mFontBuffer.reset(); } void LLButton::setImagePressed(LLPointer<LLUIImage> image) diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 4ecea6d473..890e7c2d1e 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -34,7 +34,6 @@ #include "lluictrl.h" #include "v4color.h" #include "llframetimer.h" -#include "llfontgl.h" #include "lluiimage.h" #include "lluistring.h" @@ -55,6 +54,8 @@ S32 round_up(S32 grid, S32 value); class LLUICtrlFactory; +class LLFontGL; +class LLFontVertexBuffer; // // Classes @@ -156,26 +157,29 @@ public: void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName, const LLUUID& imageID,const std::string& xmlTagName) const; - virtual bool handleUnicodeCharHere(llwchar uni_char); - virtual bool handleKeyHere(KEY key, MASK mask); - virtual bool handleMouseDown(S32 x, S32 y, MASK mask); - virtual bool handleMouseUp(S32 x, S32 y, MASK mask); - virtual bool handleHover(S32 x, S32 y, MASK mask); - virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual bool handleRightMouseUp(S32 x, S32 y, MASK mask); - virtual bool handleDoubleClick(S32 x, S32 y, MASK mask); - virtual void draw(); - /*virtual*/ bool postBuild(); + virtual bool handleUnicodeCharHere(llwchar uni_char) override; + virtual bool handleKeyHere(KEY key, MASK mask) override; + virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; + virtual bool handleMouseUp(S32 x, S32 y, MASK mask) override; + virtual bool handleHover(S32 x, S32 y, MASK mask) override; + virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask) override; + virtual bool handleRightMouseUp(S32 x, S32 y, MASK mask) override; + virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override; + virtual void draw() override; + /*virtual*/ bool postBuild() override; - virtual void onMouseLeave(S32 x, S32 y, MASK mask); - virtual void onMouseCaptureLost(); + void onVisibilityChange(bool visible) override; + void dirtyRect() override; - virtual void onCommit(); + virtual void onMouseLeave(S32 x, S32 y, MASK mask) override; + virtual void onMouseCaptureLost() override; - void setUnselectedLabelColor( const LLUIColor& c ) { mUnselectedLabelColor = c; } - void setSelectedLabelColor( const LLUIColor& c ) { mSelectedLabelColor = c; } - void setUseEllipses( bool use_ellipses ) { mUseEllipses = use_ellipses; } - void setUseFontColor( bool use_font_color) { mUseFontColor = use_font_color; } + virtual void onCommit() override; + + void setUnselectedLabelColor(const LLUIColor& c); + void setSelectedLabelColor(const LLUIColor& c); + void setUseEllipses(bool use_ellipses); + void setUseFontColor(bool use_font_color); boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); @@ -223,9 +227,8 @@ public: const std::string getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); } const std::string getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); } - void setImageColor(const std::string& color_control); void setImageColor(const LLUIColor& c); - /*virtual*/ void setColor(const LLUIColor& c); + /*virtual*/ void setColor(const LLUIColor& c) override; void setImages(const std::string &image_name, const std::string &selected_name); @@ -243,15 +246,14 @@ public: void setLabel(const std::string& label); void setLabel(const LLUIString& label); void setLabel( const LLStringExplicit& label); - virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text ); + virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text ) override; void setLabelUnselected(const LLStringExplicit& label); void setLabelSelected(const LLStringExplicit& label); - void setDisabledLabelColor( const LLUIColor& c ) { mDisabledLabelColor = c; } + void setDisabledLabelColor(const LLUIColor& c); - void setFont(const LLFontGL *font) - { mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); } - const LLFontGL* getFont() const { return mGLFont; } - const std::string& getText() const { return getCurrentLabel().getString(); } + void setFont(const LLFontGL* font); + const LLFontGL* getFont() const override { return mGLFont; } + const std::string& getText() const override { return getCurrentLabel().getString(); } S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; } bool labelIsTruncated() const; @@ -260,9 +262,7 @@ public: void setScaleImage(bool scale) { mScaleImage = scale; } bool getScaleImage() const { return mScaleImage; } - void setDropShadowedText(bool b) { mDropShadowedText = b; } - - void setBorderEnabled(bool b) { mBorderEnabled = b; } + void setDropShadowedText(bool b); void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; } @@ -278,7 +278,6 @@ public: void setCommitOnReturn(bool commit) { mCommitOnReturn = commit; } bool getCommitOnReturn() const { return mCommitOnReturn; } - static void onHeldDown(void *userdata); // to be called by gIdleCallbacks static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname); static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); static void setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); @@ -305,8 +304,6 @@ protected: commit_signal_t* mMouseUpSignal; commit_signal_t* mHeldDownSignal; - const LLFontGL* mGLFont; - S32 mMouseDownFrame; S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback F32 mHeldDownDelay; // seconds, after which held-down callbacks get called @@ -358,7 +355,6 @@ protected: bool mAutoResize; bool mUseEllipses; bool mUseFontColor; - bool mBorderEnabled; bool mFlashing; LLFontGL::HAlign mHAlign; @@ -390,8 +386,12 @@ protected: bool mForceFlashing; // Stick flashing color even if button is pressed bool mHandleRightMouse; +private: + const LLFontGL* mGLFont; + LLFontVertexBuffer mFontBuffer; + protected: - virtual std::string _getSearchText() const + virtual std::string _getSearchText() const override { return getLabelUnselected() + getToolTip(); } diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp index da5afd0386..7506cd99c0 100644 --- a/indra/llui/llchatentry.cpp +++ b/indra/llui/llchatentry.cpp @@ -45,12 +45,14 @@ LLChatEntry::LLChatEntry(const Params& p) mExpandLinesCount(p.expand_lines_count), mPrevLinesCount(0), mSingleLineMode(false), - mPrevExpandedLineCount(S32_MAX) + mPrevExpandedLineCount(S32_MAX), + mCurrentInput("") { // Initialize current history line iterator mCurrentHistoryLine = mLineHistory.begin(); mAutoIndent = false; + mShowChatMentionPicker = true; keepSelectionOnReturn(true); } @@ -189,6 +191,7 @@ bool LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) { needsReflow(); } + mCurrentInput = ""; break; case KEY_UP: @@ -196,6 +199,11 @@ bool LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) { if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin()) { + if (mCurrentHistoryLine == mLineHistory.end()) + { + mCurrentInput = getText(); + } + setText(*(--mCurrentHistoryLine)); endOfDoc(); } @@ -210,16 +218,15 @@ bool LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) case KEY_DOWN: if (mHasHistory && MASK_CONTROL == mask) { - if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1) ) + if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1)) { setText(*(++mCurrentHistoryLine)); endOfDoc(); } - else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1) ) + else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1)) { mCurrentHistoryLine++; - std::string empty(""); - setText(empty); + setText(mCurrentInput); needsReflow(); endOfDoc(); } diff --git a/indra/llui/llchatentry.h b/indra/llui/llchatentry.h index 5621ede1e7..9a0e8ee91e 100644 --- a/indra/llui/llchatentry.h +++ b/indra/llui/llchatentry.h @@ -101,6 +101,8 @@ private: S32 mExpandLinesCount; S32 mPrevLinesCount; S32 mPrevExpandedLineCount; + + std::string mCurrentInput; }; #endif /* LLCHATENTRY_H_ */ diff --git a/indra/llui/llchatmentionhelper.cpp b/indra/llui/llchatmentionhelper.cpp new file mode 100644 index 0000000000..5745389a58 --- /dev/null +++ b/indra/llui/llchatmentionhelper.cpp @@ -0,0 +1,158 @@ +/** +* @file llchatmentionhelper.cpp +* +* $LicenseInfo:firstyear=2025&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2025, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" + +#include "llchatmentionhelper.h" +#include "llfloater.h" +#include "llfloaterreg.h" +#include "lluictrl.h" + +constexpr char CHAT_MENTION_HELPER_FLOATER[] = "chat_mention_picker"; + +bool LLChatMentionHelper::isActive(const LLUICtrl* ctrl) const +{ + return mHostHandle.get() == ctrl; +} + +bool LLChatMentionHelper::isCursorInNameMention(const LLWString& wtext, S32 cursor_pos, S32* mention_start_pos) const +{ + if (cursor_pos <= 0 || cursor_pos > static_cast<S32>(wtext.size())) + return false; + + // Find the beginning of the current word + S32 start = cursor_pos - 1; + while (start > 0 && wtext[start - 1] != U32(' ') && wtext[start - 1] != U32('\n')) + { + --start; + } + + if (wtext[start] != U32('@')) + return false; + + if (mention_start_pos) + *mention_start_pos = start; + + S32 word_length = cursor_pos - start; + + if (word_length == 1) + { + return true; + } + + // Get the name after '@' + std::string name = wstring_to_utf8str(wtext.substr(start + 1, word_length - 1)); + LLStringUtil::toLower(name); + for (const auto& av_name : mAvatarNames) + { + if (av_name == name || av_name.find(name) == 0) + { + return true; + } + } + + return false; +} + +void LLChatMentionHelper::showHelper(LLUICtrl* host_ctrl, S32 local_x, S32 local_y, const std::string& av_name, std::function<void(std::string)> cb) +{ + if (mHelperHandle.isDead()) + { + LLFloater* av_picker_floater = LLFloaterReg::getInstance(CHAT_MENTION_HELPER_FLOATER); + mHelperHandle = av_picker_floater->getHandle(); + mHelperCommitConn = av_picker_floater->setCommitCallback([&](LLUICtrl* ctrl, const LLSD& param) { onCommitName(param.asString()); }); + } + setHostCtrl(host_ctrl); + mNameCommitCb = cb; + + S32 floater_x, floater_y; + if (!host_ctrl->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView)) + { + LL_WARNS() << "Cannot show helper for non-floater controls." << LL_ENDL; + return; + } + + LLFloater* av_picker_floater = mHelperHandle.get(); + LLRect rect = av_picker_floater->getRect(); + rect.setLeftTopAndSize(floater_x, floater_y + rect.getHeight(), rect.getWidth(), rect.getHeight()); + av_picker_floater->setRect(rect); + if (av_picker_floater->isShown()) + { + av_picker_floater->onOpen(LLSD().with("av_name", av_name)); + } + else + { + av_picker_floater->openFloater(LLSD().with("av_name", av_name)); + } +} + +void LLChatMentionHelper::hideHelper(const LLUICtrl* ctrl) +{ + if ((ctrl && !isActive(ctrl))) + { + return; + } + setHostCtrl(nullptr); +} + +bool LLChatMentionHelper::handleKey(const LLUICtrl* ctrl, KEY key, MASK mask) +{ + if (mHelperHandle.isDead() || !isActive(ctrl)) + { + return false; + } + + return mHelperHandle.get()->handleKey(key, mask, true); +} + +void LLChatMentionHelper::onCommitName(std::string name_url) +{ + if (!mHostHandle.isDead() && mNameCommitCb) + { + mNameCommitCb(name_url); + } +} + +void LLChatMentionHelper::setHostCtrl(LLUICtrl* host_ctrl) +{ + const LLUICtrl* pCurHostCtrl = mHostHandle.get(); + if (pCurHostCtrl != host_ctrl) + { + mHostCtrlFocusLostConn.disconnect(); + mHostHandle.markDead(); + mNameCommitCb = {}; + + if (!mHelperHandle.isDead()) + { + mHelperHandle.get()->closeFloater(); + } + + if (host_ctrl) + { + mHostHandle = host_ctrl->getHandle(); + mHostCtrlFocusLostConn = host_ctrl->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); })); + } + } +} diff --git a/indra/llui/llchatmentionhelper.h b/indra/llui/llchatmentionhelper.h new file mode 100644 index 0000000000..5f95d06f31 --- /dev/null +++ b/indra/llui/llchatmentionhelper.h @@ -0,0 +1,66 @@ +/** +* @file llchatmentionhelper.h +* @brief Header file for LLChatMentionHelper +* +* $LicenseInfo:firstyear=2025&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2025, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#pragma once + +#include "llhandle.h" +#include "llsingleton.h" + +#include <boost/signals2.hpp> + +class LLFloater; +class LLUICtrl; + +class LLChatMentionHelper : public LLSingleton<LLChatMentionHelper> +{ + LLSINGLETON(LLChatMentionHelper) {} + ~LLChatMentionHelper() override {} + +public: + + bool isActive(const LLUICtrl* ctrl) const; + bool isCursorInNameMention(const LLWString& wtext, S32 cursor_pos, S32* mention_start_pos = nullptr) const; + void showHelper(LLUICtrl* host_ctrl, S32 local_x, S32 local_y, const std::string& av_name, std::function<void(std::string)> commit_cb); + void hideHelper(const LLUICtrl* ctrl = nullptr); + + bool handleKey(const LLUICtrl* ctrl, KEY key, MASK mask); + void onCommitName(std::string name_url); + + void updateAvatarList(std::vector<std::string> av_names) { mAvatarNames = av_names; } + +protected: + void setHostCtrl(LLUICtrl* host_ctrl); + LLUICtrl* getHostCtrl() const { return mHostHandle.get(); } + +private: + LLHandle<LLUICtrl> mHostHandle; + LLHandle<LLFloater> mHelperHandle; + boost::signals2::connection mHostCtrlFocusLostConn; + boost::signals2::connection mHelperCommitConn; + std::function<void(std::string)> mNameCommitCb; + + std::vector<std::string> mAvatarNames; +}; diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index 135f128692..4068741978 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -36,8 +36,8 @@ // Constants // -const bool RADIO_STYLE = true; -const bool CHECK_STYLE = false; +constexpr bool RADIO_STYLE = true; +constexpr bool CHECK_STYLE = false; // // Classes @@ -94,7 +94,7 @@ public: // LLUICtrl interface virtual void setValue(const LLSD& value ); virtual LLSD getValue() const; - bool get() { return (bool)getValue().asBoolean(); } + bool get() const { return (bool)getValue().asBoolean(); } void set(bool value) { setValue(value); } virtual void setTentative(bool b); @@ -106,7 +106,7 @@ public: virtual void onCommit(); // LLCheckBoxCtrl interface - virtual bool toggle() { return mButton->toggleState(); } // returns new state + virtual bool toggle() { return mButton->toggleState(); } // returns new state void setBtnFocus() { mButton->setFocus(true); } diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index ee1700e009..f3876ef695 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -107,7 +107,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p) button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT); button_params.rect(p.rect); - if(mAllowTextEntry) + if (mAllowTextEntry) { button_params.pad_right(2); } @@ -121,7 +121,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p) mButton = LLUICtrlFactory::create<LLButton>(button_params); - if(mAllowTextEntry) + if (mAllowTextEntry) { //redo to compensate for button hack that leaves space for a character //unless it is a "minimal combobox"(drop down) @@ -207,14 +207,27 @@ void LLComboBox::clear() void LLComboBox::onCommit() { - if (mAllowTextEntry && getCurrentIndex() != -1) + if (LLScrollListItem* item = mList->getFirstSelected()) { - // we have selected an existing item, blitz the manual text entry with - // the properly capitalized item - mTextEntry->setValue(getSimple()); - mTextEntry->setTentative(false); + if (mAllowTextEntry && mTextEntry) + { + // we have selected an existing item, blitz the manual text entry with + // the properly capitalized item + LLSD label = item->getColumn(0)->getValue(); + mTextEntry->setValue(label); + mTextEntry->setTentative(false); + } + setControlValue(item->getValue()); + } + else if (mAllowTextEntry) + { + setControlValue(mTextEntry->getValue()); } - setControlValue(getValue()); + else + { + setControlValue(LLSD()); + } + LLUICtrl::onCommit(); } @@ -349,6 +362,13 @@ bool LLComboBox::setSimple(const LLStringExplicit& name) // virtual void LLComboBox::setValue(const LLSD& value) { + if (LLScrollListItem* item = mList->getFirstSelected()) + { + LLSD item_value = item->getValue(); + if (item_value.asString() == value.asString()) + return; + } + bool found = mList->selectByValue(value); if (found) { @@ -372,10 +392,8 @@ const std::string LLComboBox::getSimple() const { return mTextEntry->getText(); } - else - { - return res; - } + + return res; } const std::string LLComboBox::getSelectedItemLabel(S32 column) const @@ -386,24 +404,22 @@ const std::string LLComboBox::getSelectedItemLabel(S32 column) const // virtual LLSD LLComboBox::getValue() const { - LLScrollListItem* item = mList->getFirstSelected(); - if( item ) + if (LLScrollListItem* item = mList->getFirstSelected()) { return item->getValue(); } - else if (mAllowTextEntry) + + if (mAllowTextEntry) { return mTextEntry->getValue(); } - else - { - return LLSD(); - } + + return LLSD(); } void LLComboBox::setLabel(const LLStringExplicit& name) { - if ( mTextEntry ) + if (mTextEntry) { mTextEntry->setText(name); if (mList->selectItemByLabel(name, false)) @@ -498,27 +514,80 @@ void LLComboBox::setButtonVisible(bool visible) } } -bool LLComboBox::setCurrentByIndex( S32 index ) +bool LLComboBox::setCurrentByIndex(S32 index) { - bool found = mList->selectNthItem( index ); - if (found) + if (LLScrollListItem* item = mList->getItemByIndex(index)) { - setLabel(getSelectedItemLabel()); - mLastSelectedIndex = index; + if (item->getEnabled()) + { + mList->selectItem(item, -1, true); + LLSD::String label = item->getColumn(0)->getValue().asString(); + if (mTextEntry) + { + mTextEntry->setText(label); + mTextEntry->setTentative(false); + } + if (!mAllowTextEntry) + { + mButton->setLabel(label); + } + mLastSelectedIndex = index; + return true; + } } - return found; + + return false; } S32 LLComboBox::getCurrentIndex() const { - LLScrollListItem* item = mList->getFirstSelected(); - if( item ) + if (LLScrollListItem* item = mList->getFirstSelected()) { - return mList->getItemIndex( item ); + return mList->getItemIndex(item); } return -1; } +bool LLComboBox::selectNextItem() +{ + S32 last_index = getItemCount() - 1; + if (last_index < 0) + return false; + + S32 current_index = getCurrentIndex(); + if (current_index >= last_index) + return false; + + S32 new_index = llmax(current_index, -1); + while (++new_index <= last_index) + { + if (setCurrentByIndex(new_index)) + return true; + } + + return false; +} + +bool LLComboBox::selectPrevItem() +{ + S32 last_index = getItemCount() - 1; + if (last_index < 0) + return false; + + S32 current_index = getCurrentIndex(); + if (!current_index) + return false; + + S32 new_index = current_index > 0 ? current_index : last_index + 1; + while (--new_index >= 0) + { + if (setCurrentByIndex(new_index)) + return true; + } + + return false; +} + void LLComboBox::setEnabledByValue(const LLSD& value, bool enabled) { LLScrollListItem *found = mList->getItem(value); @@ -878,15 +947,46 @@ bool LLComboBox::handleUnicodeCharHere(llwchar uni_char) // virtual bool LLComboBox::handleScrollWheel(S32 x, S32 y, S32 clicks) { - if (mList->getVisible()) return mList->handleScrollWheel(x, y, clicks); + if (mList->getVisible()) + { + return mList->handleScrollWheel(x, y, clicks); + } + if (mAllowTextEntry) // We might be editable + { if (!mList->getFirstSelected()) // We aren't in the list, don't kill their text + { return false; + } + } - setCurrentByIndex(llclamp(getCurrentIndex() + clicks, 0, getItemCount() - 1)); - prearrangeList(); - onCommit(); - return true; + S32 current_index = getCurrentIndex(); + if (clicks > 0) + { + for (S32 i = 0; i < clicks; ++i) + { + if (!selectNextItem()) + break; + } + } + else + { + for (S32 i = 0; i < -clicks; ++i) + { + if (!selectPrevItem()) + break; + } + } + S32 new_index = getCurrentIndex(); + + if (new_index != current_index) + { + prearrangeList(); + onCommit(); + return true; + } + + return false; } void LLComboBox::setTextEntry(const LLStringExplicit& text) diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 9dc6fa9257..8be3eb57e4 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -163,9 +163,12 @@ public: bool remove(const std::string& name); // remove item "name", return true if found and removed - bool setCurrentByIndex( S32 index ); + bool setCurrentByIndex(S32 index); S32 getCurrentIndex() const; + bool selectNextItem(); + bool selectPrevItem(); + void setEnabledByValue(const LLSD& value, bool enabled); void createLineEditor(const Params&); diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp index 03717da80b..b10ec51f18 100644 --- a/indra/llui/llcommandmanager.cpp +++ b/indra/llui/llcommandmanager.cpp @@ -170,12 +170,14 @@ bool LLCommandManager::load() if (!parser.readXUI(commands_file, commandsParams)) { + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Unable to load xml file: " << commands_file << LL_ENDL; return false; } if (!commandsParams.validateBlock()) { + LLError::LLUserWarningMsg::showMissingFiles(); LL_ERRS() << "Invalid commands file: " << commands_file << LL_ENDL; return false; } diff --git a/indra/llui/llcontainerview.h b/indra/llui/llcontainerview.h index c6dd401e85..2675d21c22 100644 --- a/indra/llui/llcontainerview.h +++ b/indra/llui/llcontainerview.h @@ -65,21 +65,21 @@ protected: public: ~LLContainerView(); - /*virtual*/ bool postBuild(); - /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + bool postBuild() override; + bool addChild(LLView* view, S32 tab_group = 0) override; - /*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask); + bool handleDoubleClick(S32 x, S32 y, MASK mask) override; + bool handleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleMouseUp(S32 x, S32 y, MASK mask) override; - /*virtual*/ void draw(); - /*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true); - /*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options. + void draw() override; + void reshape(S32 width, S32 height, bool called_from_parent = true) override; + LLRect getRequiredRect() override; // Return the height of this object, given the set options. void setLabel(const std::string& label); void showLabel(bool show) { mShowLabel = show; } void setDisplayChildren(bool displayChildren); - bool getDisplayChildren() { return mDisplayChildren; } + bool getDisplayChildren() const { return mDisplayChildren; } void setScrollContainer(LLScrollContainer* scroll) {mScrollContainer = scroll;} private: diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index 3effc977db..9c516e23a4 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -112,8 +112,8 @@ public: virtual bool overlapsScreenChannel() { return mOverlapsScreenChannel && getVisible() && isDocked(); } virtual void setOverlapsScreenChannel(bool overlaps) { mOverlapsScreenChannel = overlaps; } - bool getUniqueDocking() { return mUniqueDocking; } - bool getUseTongue() { return mUseTongue; } + bool getUniqueDocking() const { return mUniqueDocking; } + bool getUseTongue() const { return mUseTongue; } void setUseTongue(bool use_tongue) { mUseTongue = use_tongue;} private: diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp index 11dbad8c09..1a00c03856 100644 --- a/indra/llui/lldockcontrol.cpp +++ b/indra/llui/lldockcontrol.cpp @@ -156,7 +156,7 @@ void LLDockControl::repositionDockable() } } -bool LLDockControl::isDockVisible() +bool LLDockControl::isDockVisible() const { bool res = true; diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h index 7e31330713..b6ac9c19dd 100644 --- a/indra/llui/lldockcontrol.h +++ b/indra/llui/lldockcontrol.h @@ -61,19 +61,19 @@ public: void off(); void forceRecalculatePosition(); void setDock(LLView* dockWidget); - LLView* getDock() + LLView* getDock() const { return mDockWidgetHandle.get(); } void repositionDockable(); void drawToungue(); - bool isDockVisible(); + bool isDockVisible() const; // gets a rect that bounds possible positions for a dockable control (EXT-1111) void getAllowedRect(LLRect& rect); - S32 getTongueWidth() { return mDockTongue->getWidth(); } - S32 getTongueHeight() { return mDockTongue->getHeight(); } + S32 getTongueWidth() const { return mDockTongue->getWidth(); } + S32 getTongueHeight() const { return mDockTongue->getHeight(); } private: virtual void moveDockable(); diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h index a522e63243..73211d5292 100644 --- a/indra/llui/lldraghandle.h +++ b/indra/llui/lldraghandle.h @@ -66,7 +66,7 @@ public: void setMaxTitleWidth(S32 max_width) {mMaxTitleWidth = llmin(max_width, mMaxTitleWidth); } S32 getMaxTitleWidth() const { return mMaxTitleWidth; } void setButtonsRect(const LLRect& rect){ mButtonsRect = rect; } - LLRect getButtonsRect() { return mButtonsRect; } + LLRect getButtonsRect() const { return mButtonsRect; } void setTitleVisible(bool visible); virtual void setTitle( const std::string& title ) = 0; diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index b9441a9c91..b2c59ce775 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -99,6 +99,7 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); mHelperHandle = pHelperFloater->getHandle(); mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2)); + mHelperCloseConn = pHelperFloater->setCloseCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCloseHelper(ctrl, param); }); } setHostCtrl(hostctrl_p); mEmojiCommitCb = cb; @@ -148,6 +149,16 @@ void LLEmojiHelper::onCommitEmoji(llwchar emoji) } } +void LLEmojiHelper::onCloseHelper(LLUICtrl* ctrl, const LLSD& param) +{ + mCloseSignal(ctrl, param); +} + +boost::signals2::connection LLEmojiHelper::setCloseCallback(const commit_signal_t::slot_type& cb) +{ + return mCloseSignal.connect(cb); +} + void LLEmojiHelper::setHostCtrl(LLUICtrl* hostctrl_p) { const LLUICtrl* pCurHostCtrl = mHostHandle.get(); diff --git a/indra/llui/llemojihelper.h b/indra/llui/llemojihelper.h index 2834b06061..26840eef94 100644 --- a/indra/llui/llemojihelper.h +++ b/indra/llui/llemojihelper.h @@ -51,16 +51,23 @@ public: // Eventing bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask); void onCommitEmoji(llwchar emoji); + void onCloseHelper(LLUICtrl* ctrl, const LLSD& param); + + typedef boost::signals2::signal<void(LLUICtrl* ctrl, const LLSD& param)> commit_signal_t; + boost::signals2::connection setCloseCallback(const commit_signal_t::slot_type& cb); protected: LLUICtrl* getHostCtrl() const { return mHostHandle.get(); } void setHostCtrl(LLUICtrl* hostctrl_p); private: + commit_signal_t mCloseSignal; + LLHandle<LLUICtrl> mHostHandle; LLHandle<LLFloater> mHelperHandle; boost::signals2::connection mHostCtrlFocusLostConn; boost::signals2::connection mHelperCommitConn; + boost::signals2::connection mHelperCloseConn; std::function<void(llwchar)> mEmojiCommitCb; bool mIsHideDisabled; }; diff --git a/indra/llui/llfiltereditor.h b/indra/llui/llfiltereditor.h index 686827d94c..685219c9f6 100644 --- a/indra/llui/llfiltereditor.h +++ b/indra/llui/llfiltereditor.h @@ -49,7 +49,7 @@ protected: LLFilterEditor(const Params&); friend class LLUICtrlFactory; - /*virtual*/ void handleKeystroke(); + void handleKeystroke() override; }; #endif // LL_FILTEREDITOR_H diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index c3db24c987..54f54653e2 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -85,12 +85,12 @@ void LLFlashTimer::stopFlashing() mCurrentTickCount = 0; } -bool LLFlashTimer::isFlashingInProgress() +bool LLFlashTimer::isFlashingInProgress() const { return mIsFlashingInProgress; } -bool LLFlashTimer::isCurrentlyHighlighted() +bool LLFlashTimer::isCurrentlyHighlighted() const { return mIsCurrentlyHighlighted; } diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h index b55ce53fc0..4ef70faf2d 100644 --- a/indra/llui/llflashtimer.h +++ b/indra/llui/llflashtimer.h @@ -51,8 +51,8 @@ public: void startFlashing(); void stopFlashing(); - bool isFlashingInProgress(); - bool isCurrentlyHighlighted(); + bool isFlashingInProgress() const; + bool isCurrentlyHighlighted() const; /* * Use this instead of deleting this object. * The next call to tick() will return true and that will destroy this object. diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 53f39766c6..8178bada42 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -459,6 +459,7 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) , mNoItemsCommentTextbox(NULL) , mIsConsecutiveSelection(false) , mKeepSelectionVisibleOnReshape(p.keep_selection_visible_on_reshape) + , mFocusOnItemClicked(true) { mBorderThickness = getBorderWidth(); @@ -610,7 +611,10 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) return; } - setFocus(true); + if (mFocusOnItemClicked) + { + setFocus(true); + } bool select_item = !isSelected(item_pair); @@ -1337,7 +1341,7 @@ void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) } } -bool LLFlatListViewEx::getForceShowingUnmatchedItems() +bool LLFlatListViewEx::getForceShowingUnmatchedItems() const { return mForceShowingUnmatchedItems; } diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 6d75e9f282..6271231183 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -113,7 +113,7 @@ public: }; // disable traversal when finding widget to hand focus off to - /*virtual*/ bool canFocusChildren() const { return false; } + /*virtual*/ bool canFocusChildren() const override { return false; } /** * Connects callback to signal called when Return key is pressed. @@ -121,15 +121,15 @@ public: boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); } /** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */ - virtual void reshape(S32 width, S32 height, bool called_from_parent = true); + virtual void reshape(S32 width, S32 height, bool called_from_parent = true) override; /** Returns full rect of child panel */ const LLRect& getItemsRect() const; - LLRect getRequiredRect() { return getItemsRect(); } + LLRect getRequiredRect() override { return getItemsRect(); } /** Returns distance between items */ - const S32 getItemsPad() { return mItemPad; } + const S32 getItemsPad() const { return mItemPad; } /** * Adds and item and LLSD value associated with it to the list at specified position @@ -264,13 +264,13 @@ public: void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; } /** Get number of selected items in the list */ - U32 numSelected() const {return static_cast<U32>(mSelectedItemPairs.size()); } + U32 numSelected() const { return static_cast<U32>(mSelectedItemPairs.size()); } /** Get number of (visible) items in the list */ U32 size(const bool only_visible_items = true) const; /** Removes all items from the list */ - virtual void clear(); + virtual void clear() override; /** * Removes all items that can be detached from the list but doesn't destroy @@ -294,10 +294,12 @@ public: void scrollToShowFirstSelectedItem(); - void selectFirstItem (); - void selectLastItem (); + void selectFirstItem(); + void selectLastItem(); - virtual S32 notify(const LLSD& info) ; + virtual S32 notify(const LLSD& info) override; + + void setFocusOnItemClicked(bool b) { mFocusOnItemClicked = b; } virtual ~LLFlatListView(); @@ -346,8 +348,8 @@ protected: virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection); - virtual bool canSelectAll() const; - virtual void selectAll(); + virtual bool canSelectAll() const override; + virtual void selectAll() override; virtual bool isSelected(item_pair_t* item_pair) const; @@ -364,15 +366,15 @@ protected: */ void notifyParentItemsRectChanged(); - virtual bool handleKeyHere(KEY key, MASK mask); + virtual bool handleKeyHere(KEY key, MASK mask) override; - virtual bool postBuild(); + virtual bool postBuild() override; - virtual void onFocusReceived(); + virtual void onFocusReceived() override; - virtual void onFocusLost(); + virtual void onFocusLost() override; - virtual void draw(); + virtual void draw() override; LLRect getLastSelectedItemRect(); @@ -423,6 +425,8 @@ private: bool mKeepSelectionVisibleOnReshape; + bool mFocusOnItemClicked; + /** All pairs of the list */ pairs_list_t mItemPairs; @@ -478,7 +482,7 @@ public: void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } - bool getForceShowingUnmatchedItems(); + bool getForceShowingUnmatchedItems() const; void setForceShowingUnmatchedItems(bool show); @@ -486,7 +490,7 @@ public: * Sets up new filter string and filters the list. */ void setFilterSubString(const std::string& filter_str, bool notify_parent); - std::string getFilterSubString() { return mFilterSubString; } + std::string getFilterSubString() const { return mFilterSubString; } /** * Filters the list, rearranges and notifies parent about shape changes. diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index ff174d8470..fd07b2ec5d 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1983,6 +1983,9 @@ void LLFloater::onClickCloseBtn(bool app_quitting) // virtual void LLFloater::draw() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + LL_PROFILE_ZONE_TEXT(getTitle().c_str(), getTitle().length()); + const F32 alpha = getCurrentTransparency(); // draw background @@ -2039,21 +2042,6 @@ void LLFloater::draw() LLPanel::updateDefaultBtn(); - if( getDefaultButton() ) - { - if (hasFocus() && getDefaultButton()->getEnabled()) - { - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - // is this button a direct descendent and not a nested widget (e.g. checkbox)? - bool focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && dynamic_cast<LLButton*>(focus_ctrl)->getParent() == this; - // only enable default button when current focus is not a button - getDefaultButton()->setBorderEnabled(!focus_is_child_button); - } - else - { - getDefaultButton()->setBorderEnabled(false); - } - } if (isMinimized()) { for (S32 i = 0; i < BUTTON_COUNT; i++) @@ -2177,7 +2165,7 @@ void LLFloater::setCanDrag(bool can_drag) } } -bool LLFloater::getCanDrag() +bool LLFloater::getCanDrag() const { return mDragHandle->getEnabled(); } @@ -2287,36 +2275,28 @@ void LLFloater::drawConeToOwner(F32 &context_cone_opacity, gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); - gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); - + gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); gGL.vertex2i(local_rect.mRight, local_rect.mTop); gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); - gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); - - gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); gGL.vertex2i(local_rect.mRight, local_rect.mBottom); gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); - gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); } gGL.end(); } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 9be2240f6f..9e1594bdd2 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -46,24 +46,24 @@ class LLMultiFloater; class LLFloater; -const bool RESIZE_YES = true; -const bool RESIZE_NO = false; +constexpr bool RESIZE_YES = true; +constexpr bool RESIZE_NO = false; -const bool DRAG_ON_TOP = false; -const bool DRAG_ON_LEFT = true; +constexpr bool DRAG_ON_TOP = false; +constexpr bool DRAG_ON_LEFT = true; -const bool MINIMIZE_YES = true; -const bool MINIMIZE_NO = false; +constexpr bool MINIMIZE_YES = true; +constexpr bool MINIMIZE_NO = false; -const bool CLOSE_YES = true; -const bool CLOSE_NO = false; +constexpr bool CLOSE_YES = true; +constexpr bool CLOSE_NO = false; -const bool ADJUST_VERTICAL_YES = true; -const bool ADJUST_VERTICAL_NO = false; +constexpr bool ADJUST_VERTICAL_YES = true; +constexpr bool ADJUST_VERTICAL_NO = false; -const F32 CONTEXT_CONE_IN_ALPHA = 0.f; -const F32 CONTEXT_CONE_OUT_ALPHA = 1.f; -const F32 CONTEXT_CONE_FADE_TIME = .08f; +constexpr F32 CONTEXT_CONE_IN_ALPHA = 0.f; +constexpr F32 CONTEXT_CONE_OUT_ALPHA = 1.f; +constexpr F32 CONTEXT_CONE_FADE_TIME = .08f; namespace LLFloaterEnums { @@ -228,7 +228,7 @@ public: /*virtual*/ void setIsChrome(bool is_chrome); /*virtual*/ void setRect(const LLRect &rect); void setIsSingleInstance(bool is_single_instance); - bool getIsSingleInstance() { return mSingleInstance; } + bool getIsSingleInstance() const { return mSingleInstance; } void initFloater(const Params& p); @@ -274,17 +274,17 @@ public: static bool isShown(const LLFloater* floater); static bool isVisible(const LLFloater* floater); static bool isMinimized(const LLFloater* floater); - bool isFirstLook() { return mFirstLook; } // EXT-2653: This function is necessary to prevent overlapping for secondary showed toasts + bool isFirstLook() const { return mFirstLook; } // EXT-2653: This function is necessary to prevent overlapping for secondary showed toasts virtual bool isFrontmost(); - bool isDependent() { return !mDependeeHandle.isDead(); } + bool isDependent() const { return !mDependeeHandle.isDead(); } void setCanMinimize(bool can_minimize); void setCanClose(bool can_close); void setCanTearOff(bool can_tear_off); virtual void setCanResize(bool can_resize); void setCanDrag(bool can_drag); - bool getCanDrag(); + bool getCanDrag() const; void setHost(LLMultiFloater* host); - bool isResizable() const { return mResizable; } + bool isResizable() const { return mResizable; } void setResizeLimits( S32 min_width, S32 min_height ); void getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; } @@ -347,7 +347,7 @@ public: virtual void setDocked(bool docked, bool pop_on_undock = true); virtual void setTornOff(bool torn_off) { mTornOff = torn_off; } - bool isTornOff() {return mTornOff;} + bool isTornOff() const { return mTornOff; } void setOpenPositioning(LLFloaterEnums::EOpenPositioning pos) {mPositioning = pos;} @@ -377,6 +377,10 @@ public: void enableResizeCtrls(bool enable, bool width = true, bool height = true); bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); } + + void setAutoFocus(bool focus) { mAutoFocus = focus; } // whether to automatically take focus when opened + bool getAutoFocus() const { return mAutoFocus; } + protected: void applyControlsAndPosition(LLFloater* other); @@ -401,8 +405,6 @@ protected: void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized const LLRect& getExpandedRect() const { return mExpandedRect; } - void setAutoFocus(bool focus) { mAutoFocus = focus; } // whether to automatically take focus when opened - bool getAutoFocus() const { return mAutoFocus; } LLDragHandle* getDragHandle() const { return mDragHandle; } void destroy(); // Don't call this directly. You probably want to call closeFloater() @@ -423,7 +425,6 @@ protected: private: void setForeground(bool b); // called only by floaterview void cleanupHandles(); // remove handles to dead floaters - void createMinimizeButton(); void buildButtons(const Params& p); // Images and tooltips are named in the XML, but we want to look them diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h index a36072892c..28f6e7c66b 100644 --- a/indra/llui/llfloaterreglistener.h +++ b/indra/llui/llfloaterreglistener.h @@ -30,7 +30,6 @@ #define LL_LLFLOATERREGLISTENER_H #include "lleventapi.h" -#include <string> class LLSD; diff --git a/indra/llui/llflyoutbutton.h b/indra/llui/llflyoutbutton.h index 7a49501318..73190fc984 100644 --- a/indra/llui/llflyoutbutton.h +++ b/indra/llui/llflyoutbutton.h @@ -54,7 +54,7 @@ protected: LLFlyoutButton(const Params&); friend class LLUICtrlFactory; public: - virtual void draw(); + void draw() override; void setToggleState(bool state); diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 4f3d2328aa..0d7c98294f 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -59,12 +59,6 @@ bool LLFocusableElement::handleUnicodeChar(llwchar uni_char, bool called_from_pa } // virtual -bool LLFocusableElement::handleUnicodeString(char *uni_str, bool editing, bool called_from_parent) -{ - return FALSE; -} - -// virtual bool LLFocusableElement::wantsKeyUpKeyDown() const { return false; diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index 1ca6f50354..89fee5c9f1 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -59,7 +59,6 @@ public: virtual bool handleKey(KEY key, MASK mask, bool called_from_parent); virtual bool handleKeyUp(KEY key, MASK mask, bool called_from_parent); virtual bool handleUnicodeChar(llwchar uni_char, bool called_from_parent); - virtual bool handleUnicodeString(char *uni_str, bool editing, bool called_from_parent); /** * If true this LLFocusableElement wants to receive KEYUP and KEYDOWN messages @@ -98,7 +97,7 @@ public: LLFocusableElement* getLastKeyboardFocus() const { return mLastKeyboardFocus; } bool childHasKeyboardFocus( const LLView* parent ) const; void removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus ); - bool getKeystrokesOnly() { return mKeystrokesOnly; } + bool getKeystrokesOnly() const { return mKeystrokesOnly; } void setKeystrokesOnly(bool keystrokes_only) { mKeystrokesOnly = keystrokes_only; } F32 getFocusFlashAmt() const; diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 388dc5b1ac..b664065532 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -28,6 +28,7 @@ #include "llfolderview.h" #include "llfolderviewmodel.h" +#include "llcallbacklist.h" #include "llclipboard.h" // *TODO: remove this once hack below gone. #include "llkeyboard.h" #include "lllineeditor.h" @@ -274,7 +275,11 @@ LLFolderView::~LLFolderView( void ) mRenamer = NULL; mStatusTextBox = NULL; - if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + if (mPopupMenuHandle.get()) + { + mPopupMenuHandle.get()->die(); + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } mPopupMenuHandle.markDead(); mAutoOpenItems.removeAllNodes(); @@ -1095,7 +1100,10 @@ bool LLFolderView::handleKeyHere( KEY key, MASK mask ) LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->isOpen()) { - LLMenuGL::sMenuContainer->hideMenus(); + if (LLMenuGL::sMenuContainer->hideMenus()) + { + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } } switch( key ) @@ -1340,7 +1348,10 @@ bool LLFolderView::handleUnicodeCharHere(llwchar uni_char) LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->isOpen()) { - LLMenuGL::sMenuContainer->hideMenus(); + if (LLMenuGL::sMenuContainer->hideMenus()) + { + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } } //do text search @@ -1612,7 +1623,11 @@ void LLFolderView::deleteAllChildren() { LLUI::getInstance()->removePopup(mRenamer); } - if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + if (mPopupMenuHandle.get()) + { + mPopupMenuHandle.get()->die(); + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } mPopupMenuHandle.markDead(); mScrollContainer = NULL; mRenameItem = NULL; @@ -1649,7 +1664,7 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr { LLRect local_rect = item->getLocalRect(); S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); - S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight(); + S32 label_height = getLabelFont()->getLineHeight(); // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + item->getIconPad()) : local_rect.getHeight(); @@ -1979,9 +1994,24 @@ void LLFolderView::updateMenu() LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->getVisible()) { - updateMenuOptions(menu); + // When fetching folders in bulk or in parts, each callback + // cause updateMenu individually, so make sure it gets called + // only once per frame, after callbacks are done. + // gIdleCallbacks has built in dupplicate protection. + gIdleCallbacks.addFunction(onIdleUpdateMenu, this); + } +} + +void LLFolderView::onIdleUpdateMenu(void* user_data) +{ + LLFolderView* self = (LLFolderView*)user_data; + LLMenuGL* menu = (LLMenuGL*)self->mPopupMenuHandle.get(); + if (menu) + { + self->updateMenuOptions(menu); menu->needsArrange(); // update menu height if needed } + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, self); } bool LLFolderView::isFolderSelected() diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 62ef2a0626..bdce9dec54 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -124,11 +124,11 @@ public: void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); } void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); } - bool getAllowMultiSelect() { return mAllowMultiSelect; } - bool getAllowDrag() { return mAllowDrag; } + bool getAllowMultiSelect() const { return mAllowMultiSelect; } + bool getAllowDrag() const { return mAllowDrag; } void setSingleFolderMode(bool is_single_mode) { mSingleFolderMode = is_single_mode; } - bool isSingleFolderMode() { return mSingleFolderMode; } + bool isSingleFolderMode() const { return mSingleFolderMode; } // Close all folders in the view void closeAllFolders(); @@ -142,7 +142,7 @@ public: virtual S32 getItemHeight() const; void arrangeAll() { mArrangeGeneration++; } - S32 getArrangeGeneration() { return mArrangeGeneration; } + S32 getArrangeGeneration() const { return mArrangeGeneration; } // applies filters to control visibility of items virtual void filter( LLFolderViewFilter& filter); @@ -227,27 +227,27 @@ public: void setShowSelectionContext(bool show) { mShowSelectionContext = show; } bool getShowSelectionContext(); void setShowSingleSelection(bool show); - bool getShowSingleSelection() { return mShowSingleSelection; } - F32 getSelectionFadeElapsedTime() { return mMultiSelectionFadeTimer.getElapsedTimeF32(); } - bool getUseEllipses() { return mUseEllipses; } - S32 getSelectedCount() { return (S32)mSelectedItems.size(); } + bool getShowSingleSelection() const { return mShowSingleSelection; } + F32 getSelectionFadeElapsedTime() const { return mMultiSelectionFadeTimer.getElapsedTimeF32(); } + bool getUseEllipses() const { return mUseEllipses; } + S32 getSelectedCount() const { return (S32)mSelectedItems.size(); } - void update(); // needs to be called periodically (e.g. once per frame) + void update(); // needs to be called periodically (e.g. once per frame) - bool needsAutoSelect() { return mNeedsAutoSelect && !mAutoSelectOverride; } - bool needsAutoRename() { return mNeedsAutoRename; } + bool needsAutoSelect() const { return mNeedsAutoSelect && !mAutoSelectOverride; } + bool needsAutoRename() const { return mNeedsAutoRename; } void setNeedsAutoRename(bool val) { mNeedsAutoRename = val; } void setPinningSelectedItem(bool val) { mPinningSelectedItem = val; } void setAutoSelectOverride(bool val) { mAutoSelectOverride = val; } - bool showItemLinkOverlays() { return mShowItemLinkOverlays; } + bool showItemLinkOverlays() const { return mShowItemLinkOverlays; } void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; } void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; } void setForceArrange(bool force) { mForceArrange = force; } - LLPanel* getParentPanel() { return mParentPanel.get(); } + LLPanel* getParentPanel() const { return mParentPanel.get(); } // DEBUG only void dumpSelectionInformation(); @@ -255,7 +255,7 @@ public: void setShowEmptyMessage(bool show_msg) { mShowEmptyMessage = show_msg; } - bool useLabelSuffix() { return mUseLabelSuffix; } + bool useLabelSuffix() const { return mUseLabelSuffix; } virtual void updateMenu(); void finishRenamingItem( void ); @@ -266,6 +266,7 @@ public: private: void updateMenuOptions(LLMenuGL* menu); void updateRenamerPosition(); + static void onIdleUpdateMenu(void* user_data); protected: LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container. @@ -390,7 +391,7 @@ public: virtual ~LLSelectFirstFilteredItem() {} virtual void doFolder(LLFolderViewFolder* folder); virtual void doItem(LLFolderViewItem* item); - bool wasItemSelected() { return mItemSelected || mFolderSelected; } + bool wasItemSelected() const { return mItemSelected || mFolderSelected; } protected: bool mItemSelected; bool mFolderSelected; @@ -414,6 +415,7 @@ public: virtual void doItem(LLFolderViewItem* item) {} void setApply(bool apply); void clearOpenFolders() { mOpenFolders.clear(); } + bool hasOpenFolders() { return !mOpenFolders.empty(); } protected: std::set<LLUUID> mOpenFolders; bool mApply; diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index e4f5664908..6d0cfcba95 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -23,7 +23,7 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#include "../newview/llviewerprecompiledheaders.h" +#include "linden_common.h" #include "llflashtimer.h" @@ -48,7 +48,6 @@ static LLDefaultChildRegistry::Register<LLFolderViewItem> r("folder_view_item"); // statics std::map<U8, LLFontGL*> LLFolderViewItem::sFonts; // map of styles to fonts -bool LLFolderViewItem::sColorSetInitialized = false; LLUIColor LLFolderViewItem::sFgColor; LLUIColor LLFolderViewItem::sHighlightBgColor; LLUIColor LLFolderViewItem::sFlashBgColor; @@ -58,6 +57,10 @@ LLUIColor LLFolderViewItem::sFilterBGColor; LLUIColor LLFolderViewItem::sFilterTextColor; LLUIColor LLFolderViewItem::sSuffixColor; LLUIColor LLFolderViewItem::sSearchStatusColor; +S32 LLFolderViewItem::sTopPad = 0; +LLUIImagePtr LLFolderViewItem::sFolderArrowImg; +LLUIImagePtr LLFolderViewItem::sSelectionImg; +LLFontGL* LLFolderViewItem::sSuffixFont = nullptr; // only integers can be initialized in header const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f; @@ -83,15 +86,42 @@ LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style) return rtn; } + +const LLFontGL* LLFolderViewItem::getLabelFont() +{ + if (!pLabelFont) + { + pLabelFont = getLabelFontForStyle(mLabelStyle); + } + return pLabelFont; +} //static void LLFolderViewItem::initClass() { + const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>(); + sTopPad = default_params.item_top_pad; + sFolderArrowImg = default_params.folder_arrow_image; + sSelectionImg = default_params.selection_image; + sSuffixFont = getLabelFontForStyle(LLFontGL::NORMAL); + + sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); + sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE); + sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE); + sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE); + sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE); + sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE); + sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE); + sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE); + sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE); } //static void LLFolderViewItem::cleanupClass() { sFonts.clear(); + sFolderArrowImg = nullptr; + sSelectionImg = nullptr; + sSuffixFont = nullptr; } @@ -134,6 +164,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mIsItemCut(false), mCutGeneration(0), mLabelStyle( LLFontGL::NORMAL ), + pLabelFont(nullptr), mHasVisibleChildren(false), mLocalIndentation(p.folder_indentation), mIndentation(0), @@ -158,20 +189,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mMaxFolderItemOverlap(p.max_folder_item_overlap), mDoubleClickOverride(p.double_click_override) { - if (!sColorSetInitialized) - { - sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); - sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE); - sFlashBgColor = LLUIColorTable::instance().getColor("MenuItemFlashBgColor", DEFAULT_WHITE); - sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE); - sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE); - sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE); - sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE); - sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE); - sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE); - sColorSetInitialized = true; - } - if (mViewModelItem) { mViewModelItem->setFolderViewItem(this); @@ -307,6 +324,7 @@ void LLFolderViewItem::refresh() LLFolderViewModelItem& vmi = *getViewModelItem(); mLabel = utf8str_to_wstring(vmi.getDisplayName()); + mLabelFontBuffer.reset(); setToolTip(vmi.getName()); // icons are slightly expensive to get, can be optimized // see LLInventoryIcon::getIcon() @@ -319,7 +337,9 @@ void LLFolderViewItem::refresh() // Very Expensive! // Can do a number of expensive checks, like checking active motions, wearables or friend list mLabelStyle = vmi.getLabelStyle(); + pLabelFont = nullptr; // refresh can be called from a coro, don't use getLabelFontForStyle, coro trips font list tread safety mLabelSuffix = utf8str_to_wstring(vmi.getLabelSuffix()); + mSuffixFontBuffer.reset(); } // Dirty the filter flag of the model from the view (CHUI-849) @@ -344,6 +364,7 @@ void LLFolderViewItem::refreshSuffix() // Very Expensive! // Can do a number of expensive checks, like checking active motions, wearables or friend list mLabelStyle = vmi->getLabelStyle(); + pLabelFont = nullptr; mLabelSuffix = utf8str_to_wstring(vmi->getLabelSuffix()); } @@ -736,19 +757,17 @@ bool LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, return handled; } -void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color) +void LLFolderViewItem::drawOpenFolderArrow() { //--------------------------------------------------------------------------------// // Draw open folder arrow // - const S32 TOP_PAD = default_params.item_top_pad; if (hasVisibleChildren() || !isFolderComplete()) { - LLUIImage* arrow_image = default_params.folder_arrow_image; gl_draw_scaled_rotated_image( - mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD, - mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), fg_color); + mIndentation, getRect().getHeight() - mArrowSize - mTextPad - sTopPad, + mArrowSize, mArrowSize, mControlLabelRotation, sFolderArrowImg->getImage(), sFgColor); } } @@ -764,7 +783,7 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L /*virtual*/ bool LLFolderViewItem::isFadeItem() { - LLClipboard& clipboard = LLClipboard::instance(); + static const LLClipboard& clipboard = LLClipboard::instance(); // Make it a 'simpleton'? if (mCutGeneration != clipboard.getGeneration()) { mCutGeneration = clipboard.getGeneration(); @@ -775,8 +794,9 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L return mIsItemCut; } -void LLFolderViewItem::drawHighlight(const bool showContent, const bool hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, - const LLUIColor &focusOutlineColor, const LLUIColor &mouseOverColor) +void LLFolderViewItem::drawHighlight(bool showContent, bool hasKeyboardFocus, + const LLUIColor& selectColor, const LLUIColor& flashColor, + const LLUIColor& focusOutlineColor, const LLUIColor& mouseOverColor) { const S32 focus_top = getRect().getHeight(); const S32 focus_bottom = getRect().getHeight() - mItemHeight; @@ -784,7 +804,7 @@ void LLFolderViewItem::drawHighlight(const bool showContent, const bool hasKeybo const S32 FOCUS_LEFT = 1; // Determine which background color to use for highlighting - const LLUIColor& bgColor = (isFlashing() ? flashColor : selectColor); + const LLUIColor& bgColor = isFlashing() ? flashColor : selectColor; //--------------------------------------------------------------------------------// // Draw highlight for selected items @@ -792,7 +812,6 @@ void LLFolderViewItem::drawHighlight(const bool showContent, const bool hasKeybo // items if mShowSingleSelection is false. // if (isHighlightAllowed()) - { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -801,7 +820,7 @@ void LLFolderViewItem::drawHighlight(const bool showContent, const bool hasKeybo { LLColor4 bg_color = bgColor; // do time-based fade of extra objects - F32 fade_time = (getRoot() ? getRoot()->getSelectionFadeElapsedTime() : 0.0f); + F32 fade_time = getRoot() ? getRoot()->getSelectionFadeElapsedTime() : 0.f; if (getRoot() && getRoot()->getShowSingleSelection()) { // fading out @@ -890,7 +909,7 @@ void LLFolderViewItem::drawLabel(const LLFontGL * font, const F32 x, const F32 y //--------------------------------------------------------------------------------// // Draw the actual label text // - font->render(mLabel, 0, x, y, color, + mLabelFontBuffer.render(font, mLabel, 0, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, /*use_ellipses*/true); } @@ -900,16 +919,14 @@ void LLFolderViewItem::draw() const bool show_context = (getRoot() ? getRoot()->getShowSelectionContext() : false); const bool filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : false); // If we have keyboard focus, draw selection filled - const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>(); - const S32 TOP_PAD = default_params.item_top_pad; - - const LLFontGL* font = getLabelFontForStyle(mLabelStyle); + const LLFontGL* font = getLabelFont(); + S32 line_height = font->getLineHeight(); getViewModelItem()->update(); - if(!mSingleFolderMode) + if (!mSingleFolderMode) { - drawOpenFolderArrow(default_params, sFgColor); + drawOpenFolderArrow(); } drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor); @@ -918,18 +935,19 @@ void LLFolderViewItem::draw() // Draw open icon // const S32 icon_x = mIndentation + mArrowSize + mTextPad; + const S32 rect_height = getRect().getHeight(); if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders { - mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1); + mIconOpen->draw(icon_x, rect_height - mIconOpen->getHeight() - sTopPad + 1); } else if (mIcon) { - mIcon->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); + mIcon->draw(icon_x, rect_height - mIcon->getHeight() - sTopPad + 1); } if (mIconOverlay && getRoot()->showItemLinkOverlays()) { - mIconOverlay->draw(icon_x, getRect().getHeight() - mIcon->getHeight() - TOP_PAD + 1); + mIconOverlay->draw(icon_x, rect_height - mIcon->getHeight() - sTopPad + 1); } //--------------------------------------------------------------------------------// @@ -940,26 +958,24 @@ void LLFolderViewItem::draw() return; } - auto filter_string_length = mViewModelItem->hasFilterStringMatch() ? static_cast<S32>(mViewModelItem->getFilterStringSize()) : 0; + S32 filter_string_length = mViewModelItem->hasFilterStringMatch() ? (S32)mViewModelItem->getFilterStringSize() : 0; F32 right_x = 0; - F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; + F32 y = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad; F32 text_left = (F32)getLabelXPos(); LLWString combined_string = mLabel + mLabelSuffix; - const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL); S32 filter_offset = static_cast<S32>(mViewModelItem->getFilterStringOffset()); if (filter_string_length > 0) { - S32 bottom = getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD; - S32 top = getRect().getHeight() - TOP_PAD; - if(mLabelSuffix.empty() || (font == suffix_font)) + S32 bottom = rect_height - line_height - 3 - sTopPad; + S32 top = rect_height - sTopPad; + if(mLabelSuffix.empty() || (font == sSuffixFont)) { - S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, static_cast<S32>(mViewModelItem->getFilterStringOffset())) - 2; - S32 right = left + font->getWidth(combined_string.c_str(), static_cast<S32>(mViewModelItem->getFilterStringOffset()), filter_string_length) + 2; + S32 left = ll_round(text_left) + font->getWidth(combined_string.c_str(), 0, filter_offset) - 2; + S32 right = left + font->getWidth(combined_string.c_str(), filter_offset, filter_string_length) + 2; - LLUIImage* box_image = default_params.selection_image; - LLRect box_rect(left, top, right, bottom); - box_image->draw(box_rect, sFilterBGColor); + LLRect box_rect(left, top, right, bottom); + sSelectionImg->draw(box_rect, sFilterBGColor); } else { @@ -968,19 +984,17 @@ void LLFolderViewItem::draw() { S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, llmin(filter_offset, (S32)mLabel.size()))) - 2; S32 right = left + (S32)font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length) + 2; - LLUIImage* box_image = default_params.selection_image; LLRect box_rect(left, top, right, bottom); - box_image->draw(box_rect, sFilterBGColor); + sSelectionImg->draw(box_rect, sFilterBGColor); } S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length; if(suffix_filter_length > 0) { S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size()); - S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset)) - 2; - S32 right = left + (S32)suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2; - LLUIImage* box_image = default_params.selection_image; + S32 left = (S32)(ll_round(text_left) + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset)) - 2; + S32 right = left + (S32)sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length) + 2; LLRect box_rect(left, top, right, bottom); - box_image->draw(box_rect, sFilterBGColor); + sSelectionImg->draw(box_rect, sFilterBGColor); } } } @@ -999,9 +1013,9 @@ void LLFolderViewItem::draw() // if (!mLabelSuffix.empty()) { - suffix_font->render( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : sSuffixColor.get(), - LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - S32_MAX, S32_MAX, &right_x); + mSuffixFontBuffer.render(sSuffixFont, mLabelSuffix, 0, right_x, y, isFadeItem() ? color : sSuffixColor.get(), + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, + S32_MAX, S32_MAX, &right_x); } //--------------------------------------------------------------------------------// @@ -1009,10 +1023,10 @@ void LLFolderViewItem::draw() // if (filter_string_length > 0) { - if(mLabelSuffix.empty() || (font == suffix_font)) + if(mLabelSuffix.empty() || (font == sSuffixFont)) { F32 match_string_left = text_left + font->getWidthF32(combined_string.c_str(), 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string.c_str(), filter_offset, filter_string_length); - F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; + F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad; font->render(combined_string, filter_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, filter_string_length, S32_MAX, &right_x); @@ -1023,7 +1037,7 @@ void LLFolderViewItem::draw() if(label_filter_length > 0) { F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel.c_str(), filter_offset, label_filter_length); - F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; + F32 yy = (F32)rect_height - line_height - (F32)mTextPad - (F32)sTopPad; font->render(mLabel, filter_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x); @@ -1033,9 +1047,9 @@ void LLFolderViewItem::draw() if(suffix_filter_length > 0) { S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size()); - F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + suffix_font->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length); - F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; - suffix_font->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, + F32 match_string_left = text_left + font->getWidthF32(mLabel.c_str(), 0, static_cast<S32>(mLabel.size())) + sSuffixFont->getWidthF32(mLabelSuffix.c_str(), 0, suffix_offset + suffix_filter_length) - sSuffixFont->getWidthF32(mLabelSuffix.c_str(), suffix_offset, suffix_filter_length); + F32 yy = (F32)rect_height - sSuffixFont->getLineHeight() - (F32)mTextPad - (F32)sTopPad; + sSuffixFont->render(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, suffix_filter_length, S32_MAX, &right_x); } diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 60cdac3ab9..2ee018a90a 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -29,6 +29,7 @@ #include "llflashtimer.h" #include "llview.h" #include "lluiimage.h" +#include "llfontvertexbuffer.h" class LLFolderView; class LLFolderViewModelItem; @@ -134,7 +135,6 @@ protected: LLUIColor mFontHighlightColor; // For now assuming all colors are the same in derived classes. - static bool sColorSetInitialized; static LLUIColor sFgColor; static LLUIColor sFgDisabledColor; static LLUIColor sHighlightBgColor; @@ -154,9 +154,10 @@ protected: virtual bool isHighlightActive(); virtual bool isFadeItem(); virtual bool isFlashing() { return false; } - virtual void setFlashState(bool) { } + virtual void setFlashState(bool, bool) { } static LLFontGL* getLabelFontForStyle(U8 style); + const LLFontGL* getLabelFont(); bool mIsSelected; @@ -281,7 +282,7 @@ public: // Does not need filter update virtual void refreshSuffix(); - bool isSingleFolderMode() { return mSingleFolderMode; } + bool isSingleFolderMode() const { return mSingleFolderMode; } // LLView functionality virtual bool handleRightMouseDown( S32 x, S32 y, MASK mask ); @@ -296,9 +297,9 @@ public: // virtual void handleDropped(); virtual void draw(); - void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color); - void drawHighlight(const bool showContent, const bool hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, const LLUIColor &outlineColor, const LLUIColor &mouseOverColor); - void drawLabel(const LLFontGL * font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x); + void drawOpenFolderArrow(); + void drawHighlight(bool showContent, bool hasKeyboardFocus, const LLUIColor& selectColor, const LLUIColor& flashColor, const LLUIColor& outlineColor, const LLUIColor& mouseOverColor); + void drawLabel(const LLFontGL* font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x); virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, EDragAndDropType cargo_type, void* cargo_data, @@ -307,6 +308,14 @@ public: private: static std::map<U8, LLFontGL*> sFonts; // map of styles to fonts + static S32 sTopPad; + static LLUIImagePtr sFolderArrowImg; + static LLUIImagePtr sSelectionImg; + static LLFontGL* sSuffixFont; + + LLFontVertexBuffer mLabelFontBuffer; + LLFontVertexBuffer mSuffixFontBuffer; + LLFontGL* pLabelFont{nullptr}; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -406,9 +415,6 @@ public: // doesn't delete it. virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true); - // This function is called by a child that needs to be resorted. - void resort(LLFolderViewItem* item); - void setAutoOpenCountdown(F32 countdown) { mAutoOpenCountdown = countdown; } // folders can be opened. This will usually be called by internal diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index b8d6d89971..9372818ca5 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -292,6 +292,7 @@ public: dirtyFilter(); requestSort(); } + virtual void removeChild(LLFolderViewModelItem* child) { mChildren.remove(child); diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index 7bf43c22c1..2bea8fb4ed 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -170,7 +170,7 @@ std::string LLKeywords::getAttribute(std::string_view key) return (it != mAttributes.end()) ? it->second : ""; } -LLUIColor LLKeywords::getColorGroup(std::string_view key_in) +LLUIColor LLKeywords::getColorGroup(std::string_view key_in) const { std::string color_group = "ScriptText"; if (key_in == "functions") diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h index 328561c92a..5892238593 100644 --- a/indra/llui/llkeywords.h +++ b/indra/llui/llkeywords.h @@ -111,8 +111,8 @@ public: ~LLKeywords(); void clearLoaded() { mLoaded = false; } - LLUIColor getColorGroup(std::string_view key_in); - bool isLoaded() const { return mLoaded; } + LLUIColor getColorGroup(std::string_view key_in) const; + bool isLoaded() const { return mLoaded; } void findSegments(std::vector<LLTextSegmentPtr> *seg_list, const LLWString& text, diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 1c59938f90..fe0591ce4b 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -36,8 +36,8 @@ #include "lliconctrl.h" #include "boost/foreach.hpp" -static const F32 MIN_FRACTIONAL_SIZE = 0.00001f; -static const F32 MAX_FRACTIONAL_SIZE = 1.f; +static constexpr F32 MIN_FRACTIONAL_SIZE = 0.00001f; +static constexpr F32 MAX_FRACTIONAL_SIZE = 1.f; static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack"); static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel"); diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index 8459921c60..9e3536aaff 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -75,9 +75,6 @@ public: /*virtual*/ bool addChild(LLView* child, S32 tab_group = 0); /*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true); - - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); - typedef enum e_animate { NO_ANIMATE, @@ -86,7 +83,7 @@ public: void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE); void collapsePanel(LLPanel* panel, bool collapsed = true); - S32 getNumPanels() { return static_cast<S32>(mPanels.size()); } + S32 getNumPanels() const { return static_cast<S32>(mPanels.size()); } void updateLayout(); @@ -190,7 +187,6 @@ public: bool isCollapsed() const { return mCollapsed;} void setOrientation(LLView::EOrientation orientation); - void storeOriginalDim(); void setIgnoreReshape(bool ignore) { mIgnoreReshape = ignore; } diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index ac7948f735..45dab88e87 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -436,6 +436,9 @@ void LLLineEditor::setText(const LLStringExplicit &new_text, bool use_size_limit { mText.assign(utf8str_symbol_truncate(truncated_utf8, mMaxLengthChars)); } + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); if (all_selected) { @@ -617,6 +620,10 @@ void LLLineEditor::replaceWithSuggestion(U32 index) mText.insert(it->first, suggestion); setCursor(it->first + (S32)suggestion.length()); + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); + break; } } @@ -969,6 +976,10 @@ void LLLineEditor::removeChar() mText.erase(getCursor() - 1, 1); setCursor(getCursor() - 1); + + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); } else { @@ -992,6 +1003,10 @@ void LLLineEditor::addChar(const llwchar uni_char) return; mText.erase(getCursor(), 1); + + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); } S32 cur_bytes = static_cast<S32>(mText.getString().size()); @@ -1022,6 +1037,10 @@ void LLLineEditor::addChar(const llwchar uni_char) mText.insert(getCursor(), w_buf); setCursor(getCursor() + 1); + + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); } else { @@ -1031,25 +1050,6 @@ void LLLineEditor::addChar(const llwchar uni_char) getWindow()->hideCursorUntilMouseMove(); } -void LLLineEditor::addString(char *s, bool editing) -{ - if (hasSelection()) - deleteSelection(); - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) { - if (!prevalidateInput(mText.getWString() - .substr(getCursor(), 1))) - return; - mText.erase(getCursor(), 1); - } else if (editing) { - mText.clear(); - setCursor(0); - } - mText.insert(getCursor(), utf8str_to_wstring(s)); - if (editing) setCursor(strlen(s)); - else setCursor(getCursor() + 1); - getWindow()->hideCursorUntilMouseMove(); -} - // Extends the selection box to the new cursor position void LLLineEditor::extendSelection( S32 new_cursor_pos ) { @@ -1205,6 +1205,10 @@ void LLLineEditor::deleteSelection() mText.erase(left_pos, selection_length); deselect(); setCursor(left_pos); + + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); } } @@ -1365,6 +1369,10 @@ void LLLineEditor::pasteHelper(bool is_primary) setCursor( getCursor() + (S32)clean_string.length() ); deselect(); + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); + // Validate new string and rollback the if needed. bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString()); if (need_to_rollback) @@ -1525,6 +1533,10 @@ bool LLLineEditor::handleSpecialKey(KEY key, MASK mask) { mText.assign(*(--mCurrentHistoryLine)); setCursorToEnd(); + + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); } else { @@ -1542,6 +1554,10 @@ bool LLLineEditor::handleSpecialKey(KEY key, MASK mask) { mText.assign( *(++mCurrentHistoryLine) ); setCursorToEnd(); + + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); } else { @@ -1704,36 +1720,6 @@ bool LLLineEditor::handleUnicodeCharHere(llwchar uni_char) return handled; } -bool LLLineEditor::handleUnicodeStringHere(char *uni_str, bool editing) -{ - auto handled = FALSE; - - if ((gFocusMgr.getKeyboardFocus() == this) - && getVisible() && !mReadOnly) { - handled = TRUE; - LLLineEditorRollback rollback(this); - - addString(uni_str, editing); - - mKeystrokeTimer.reset(); - deselect(); - auto need_to_rollback = mPrevalidator - && !mPrevalidator.validate(mText.getWString()); - - if (need_to_rollback) { - rollback.doRollback(this); - LLUI::getInstance()->reportBadKeystroke(); - mPrevalidator.showLastErrorUsingTimeout(); - } - - if (!need_to_rollback && handled) { - onKeystroke(); - mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); - } - } - - return handled; -} bool LLLineEditor::canDoDelete() const { @@ -1946,7 +1932,8 @@ void LLLineEditor::draw() if( select_left > mScrollHPos ) { // unselected, left side - rendered_text = mGLFont->render( + rendered_text = mFontBufferPreSelection.render( + mGLFont, mText, mScrollHPos, rendered_pixels_right, text_bottom, text_color, @@ -1968,7 +1955,8 @@ void LLLineEditor::draw() gl_rect_2d(ll_round(rendered_pixels_right), cursor_top, ll_round(rendered_pixels_right)+width, cursor_bottom, color); LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); - rendered_text += mGLFont->render( + rendered_text += mFontBufferSelection.render( + mGLFont, mText, mScrollHPos + rendered_text, rendered_pixels_right, text_bottom, tmp_color, @@ -1983,7 +1971,8 @@ void LLLineEditor::draw() if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) ) { // unselected, right side - rendered_text += mGLFont->render( + rendered_text += mFontBufferPostSelection.render( + mGLFont, mText, mScrollHPos + rendered_text, rendered_pixels_right, text_bottom, text_color, @@ -1997,7 +1986,8 @@ void LLLineEditor::draw() } else { - rendered_text = mGLFont->render( + rendered_text = mFontBufferPreSelection.render( + mGLFont, mText, mScrollHPos, rendered_pixels_right, text_bottom, text_color, @@ -2157,7 +2147,8 @@ void LLLineEditor::draw() //to give indication that it is not text you typed in if (0 == mText.length() && (mReadOnly || mShowLabelFocused)) { - mGLFont->render(mLabel.getWString(), 0, + mFontBufferLabel.render(mGLFont, + mLabel.getWString(), 0, (F32)mTextLeftEdge, (F32)text_bottom, label_color, LLFontGL::LEFT, @@ -2182,7 +2173,8 @@ void LLLineEditor::draw() // draw label if no text provided if (0 == mText.length()) { - mGLFont->render(mLabel.getWString(), 0, + mFontBufferLabel.render(mGLFont, + mLabel.getWString(), 0, (F32)mTextLeftEdge, (F32)text_bottom, label_color, LLFontGL::LEFT, @@ -2453,12 +2445,16 @@ void LLLineEditor::setKeystrokeCallback(callback_t callback, void* user_data) bool LLLineEditor::setTextArg( const std::string& key, const LLStringExplicit& text ) { mText.setArg(key, text); + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); return true; } bool LLLineEditor::setLabelArg( const std::string& key, const LLStringExplicit& text ) { mLabel.setArg(key, text); + mFontBufferLabel.reset(); return true; } @@ -2509,9 +2505,24 @@ void LLLineEditor::resetPreedit() if (hasPreeditString()) { const S32 preedit_pos = mPreeditPositions.front(); - mText.erase(preedit_pos, mPreeditPositions.back() - preedit_pos); - mText.insert(preedit_pos, mPreeditOverwrittenWString); - setCursor(preedit_pos); + const S32 end = mPreeditPositions.back(); + const S32 len = end - preedit_pos; + const S32 size = mText.length(); + if (preedit_pos < size + && end <= size + && preedit_pos >= 0 + && len > 0) + { + mText.erase(preedit_pos, len); + mText.insert(preedit_pos, mPreeditOverwrittenWString); + setCursor(preedit_pos); + } + else + { + LL_WARNS() << "Index out of bounds. Start: " << preedit_pos + << ", end:" << end + << ", full string length: " << size << LL_ENDL; + } mPreeditWString.clear(); mPreeditOverwrittenWString.clear(); @@ -2557,6 +2568,9 @@ void LLLineEditor::updatePreedit(const LLWString &preedit_string, mPreeditOverwrittenWString.clear(); } mText.insert(insert_preedit_at, mPreeditWString); + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); mPreeditStandouts = preedit_standouts; diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 3a39a7363d..7533f76f1d 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -40,6 +40,7 @@ #include "llframetimer.h" #include "lleditmenuhandler.h" +#include "llfontvertexbuffer.h" #include "llspellcheckmenuhandler.h" #include "lluictrl.h" #include "lluiimage.h" @@ -133,7 +134,6 @@ public: /*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask) override; /*virtual*/ bool handleKeyHere(KEY key, MASK mask) override; /*virtual*/ bool handleUnicodeCharHere(llwchar uni_char) override; - /*virtual*/ bool handleUnicodeStringHere(char *uni_str, bool editing) override; /*virtual*/ void onMouseCaptureLost() override; // LLEditMenuHandler overrides @@ -301,14 +301,11 @@ public: void removeChar(); void addChar(const llwchar c); - void addString(char *s, bool editing); void setCursorAtLocalPos(S32 local_mouse_x); S32 findPixelNearestPos(S32 cursor_offset = 0) const; S32 calcCursorPos(S32 mouse_x); bool handleSpecialKey(KEY key, MASK mask); bool handleSelectionKey(KEY key, MASK mask); - bool handleControlKey(KEY key, MASK mask); - S32 handleCommitKey(KEY key, MASK mask); void updateTextPadding(); // Draw the background image depending on enabled/focused state. @@ -346,6 +343,10 @@ protected: LLViewBorder* mBorder; const LLFontGL* mGLFont; + LLFontVertexBuffer mFontBufferPreSelection; + LLFontVertexBuffer mFontBufferSelection; + LLFontVertexBuffer mFontBufferPostSelection; + LLFontVertexBuffer mFontBufferLabel; S32 mMaxLengthBytes; // Max length of the UTF8 string in bytes S32 mMaxLengthChars; // Maximum number of characters in the string S32 mCursorPos; // I-beam is just after the mCursorPos-th character. @@ -441,7 +442,7 @@ private: mText = ed->getText(); } - void doRollback( LLLineEditor* ed ) + void doRollback(LLLineEditor* ed) const { ed->mCursorPos = mCursorPos; ed->mScrollHPos = mScrollHPos; @@ -452,7 +453,7 @@ private: ed->mPrevText = mText; } - std::string getText() { return mText; } + std::string getText() const { return mText; } private: std::string mText; diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index a77ae7dae7..3f96b28246 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -65,8 +65,8 @@ public: boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); - /*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleKeyHere(KEY key, MASK mask ); + bool handleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleKeyHere(KEY key, MASK mask) override; void hideMenu(); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 69ffa9a94f..c11b42a348 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -508,7 +508,7 @@ void LLMenuItemGL::draw( void ) // Highlight if needed if( ll::ui::SearchableControl::getHighlighted() ) - color = ll::ui::SearchableControl::getHighlightColor(); + color = ll::ui::SearchableControl::getHighlightFontColor(); // Draw the text on top. if (mBriefItem) diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 66f84393fe..ff9456acc6 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -439,8 +439,6 @@ protected: public: virtual ~LLMenuGL( void ); - void parseChildXML(LLXMLNodePtr child, LLView* parent); - // LLView Functionality /*virtual*/ bool handleUnicodeCharHere( llwchar uni_char ); /*virtual*/ bool handleHover( S32 x, S32 y, MASK mask ); diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index a7f9b8b2d9..f53e22c349 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -390,7 +390,7 @@ LLFloater* LLMultiFloater::getActiveFloater() return (LLFloater*)mTabContainer->getCurrentPanel(); } -S32 LLMultiFloater::getFloaterCount() +S32 LLMultiFloater::getFloaterCount() const { return mTabContainer->getTabCount(); } diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h index eb0f917695..e0cd58aa3f 100644 --- a/indra/llui/llmultifloater.h +++ b/indra/llui/llmultifloater.h @@ -66,7 +66,7 @@ public: virtual LLFloater* getActiveFloater(); virtual bool isFloaterFlashing(LLFloater* floaterp); - virtual S32 getFloaterCount(); + virtual S32 getFloaterCount() const; virtual void setFloaterFlashing(LLFloater* floaterp, bool flashing); virtual bool closeAllFloaters(); //Returns false if the floater could not be closed due to pending confirmation dialogs diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h index b2bfc8bc84..af255bcc8f 100644 --- a/indra/llui/llmultislider.h +++ b/indra/llui/llmultislider.h @@ -117,10 +117,10 @@ public: /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) override; /*virtual*/ void draw() override; - S32 getMaxNumSliders() { return mMaxNumSliders; } - S32 getCurNumSliders() { return static_cast<S32>(mValue.size()); } - F32 getOverlapThreshold() { return mOverlapThreshold; } - bool canAddSliders() { return mValue.size() < mMaxNumSliders; } + S32 getMaxNumSliders() const { return mMaxNumSliders; } + S32 getCurNumSliders() const { return static_cast<S32>(mValue.size()); } + F32 getOverlapThreshold() const { return mOverlapThreshold; } + bool canAddSliders() const { return mValue.size() < mMaxNumSliders; } protected: diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h index dec6cb48b9..2c2bc5e4d9 100644 --- a/indra/llui/llmultisliderctrl.h +++ b/indra/llui/llmultisliderctrl.h @@ -124,10 +124,10 @@ public: F32 getMinValue() const { return mMultiSlider->getMinValue(); } F32 getMaxValue() const { return mMultiSlider->getMaxValue(); } - S32 getMaxNumSliders() { return mMultiSlider->getMaxNumSliders(); } - S32 getCurNumSliders() { return mMultiSlider->getCurNumSliders(); } - F32 getOverlapThreshold() { return mMultiSlider->getOverlapThreshold(); } - bool canAddSliders() { return mMultiSlider->canAddSliders(); } + S32 getMaxNumSliders() const { return mMultiSlider->getMaxNumSliders(); } + S32 getCurNumSliders() const { return mMultiSlider->getCurNumSliders(); } + F32 getOverlapThreshold() const { return mMultiSlider->getOverlapThreshold(); } + bool canAddSliders() const { return mMultiSlider->canAddSliders(); } void setLabel(const std::string& label) { if (mLabelBox) mLabelBox->setText(label); } void setLabelColor(const LLUIColor& c) { mTextEnabledColor = c; } @@ -147,7 +147,6 @@ public: static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata); static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); - static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); private: void updateText(); diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index cd80e7f63f..a05feab1d9 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -614,6 +614,13 @@ void LLNotification::cancel() LLSD LLNotification::getResponseTemplate(EResponseTemplateType type) { LLSD response = LLSD::emptyMap(); + + if (!mForm) + { + LL_WARNS("Notifications") << "Null form when getting response template for notification " << getName() << LL_ENDL; + return response; + } + for (S32 element_idx = 0; element_idx < mForm->getNumElements(); ++element_idx) @@ -1249,9 +1256,26 @@ LLNotifications::LLNotifications() LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount(); } + +LLNotifications::~LLNotifications() +{ + // Clear explicitly, something in ~LLNotifications() crashes so narrowing down suspects + pHistoryChannel = nullptr; + pExpirationChannel = nullptr; + mGlobalStrings.clear(); + mTemplates.clear(); + mVisibilityRules.clear(); + mUniqueNotifications.clear(); + mListener = nullptr; +} + void LLNotifications::clear() { - mDefaultChannels.clear(); + mDefaultChannels.clear(); + // At this point mTemplates still gets used by lingering notifications + // to do responses (ex: group notice will call forceResponse()), but + // since network should be down and everything save, it's questionable + // whether it should stay that way } // The expiration channel gets all notifications that are cancelled @@ -1464,6 +1488,13 @@ bool LLNotifications::templateExists(std::string_view name) void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option) { LLNotificationPtr temp_notify(new LLNotification(params)); + + if (!temp_notify->getForm()) + { + LL_WARNS("Notifications") << "Cannot force response for notification with null form: " << (std::string)params.name << LL_ENDL; + return; + } + LLSD response = temp_notify->getResponseTemplate(); LLSD selected_item = temp_notify->getForm()->getElement(option); @@ -1555,7 +1586,7 @@ bool LLNotifications::loadTemplates() gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); if (search_paths.empty()) { - LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"), LLError::LLUserWarningMsg::ERROR_MISSING_FILES); LL_ERRS() << "Problem finding notifications.xml" << LL_ENDL; } @@ -1565,7 +1596,7 @@ bool LLNotifications::loadTemplates() if (!success || root.isNull() || !root->hasName( "notifications" )) { - LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"), LLError::LLUserWarningMsg::ERROR_MISSING_FILES); LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; return false; } @@ -1576,7 +1607,7 @@ bool LLNotifications::loadTemplates() if(!params.validateBlock()) { - LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"), LLError::LLUserWarningMsg::ERROR_MISSING_FILES); LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL; return false; } @@ -1643,7 +1674,7 @@ bool LLNotifications::loadVisibilityRules() if(!params.validateBlock()) { - LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"), LLError::LLUserWarningMsg::ERROR_MISSING_FILES); LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL; return false; } diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 46286457cf..3c8e1e85fa 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -247,7 +247,6 @@ public: LLNotificationForm(const LLSD& sd); LLNotificationForm(const std::string& name, const Params& p); - void fromLLSD(const LLSD& sd); LLSD asLLSD() const; S32 getNumElements() { return static_cast<S32>(mFormData.size()); } @@ -266,8 +265,8 @@ public: bool getIgnored(); void setIgnored(bool ignored); - EIgnoreType getIgnoreType() { return mIgnore; } - std::string getIgnoreMessage() { return mIgnoreMsg; } + EIgnoreType getIgnoreType()const { return mIgnore; } + std::string getIgnoreMessage() const { return mIgnoreMsg; } private: LLSD mFormData; @@ -887,7 +886,7 @@ class LLNotifications : { LLSINGLETON(LLNotifications); LOG_CLASS(LLNotifications); - virtual ~LLNotifications() {} + virtual ~LLNotifications(); public: @@ -971,8 +970,6 @@ private: /*virtual*/ void initSingleton() override; /*virtual*/ void cleanupSingleton() override; - void loadPersistentNotifications(); - bool expirationFilter(LLNotificationPtr pNotification); bool expirationHandler(const LLSD& payload); bool uniqueFilter(LLNotificationPtr pNotification); diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 8e96bdde80..db314cae0f 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -242,20 +242,6 @@ void LLPanel::draw() void LLPanel::updateDefaultBtn() { - if( mDefaultBtn) - { - if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled()) - { - LLButton* buttonp = dynamic_cast<LLButton*>(gFocusMgr.getKeyboardFocus()); - bool focus_is_child_button = buttonp && buttonp->getCommitOnReturn(); - // only enable default button when current focus is not a return-capturing button - mDefaultBtn->setBorderEnabled(!focus_is_child_button); - } - else - { - mDefaultBtn->setBorderEnabled(false); - } - } } void LLPanel::refresh() @@ -266,15 +252,7 @@ void LLPanel::refresh() void LLPanel::setDefaultBtn(LLButton* btn) { - if (mDefaultBtn && mDefaultBtn->getEnabled()) - { - mDefaultBtn->setBorderEnabled(false); - } mDefaultBtn = btn; - if (mDefaultBtn) - { - mDefaultBtn->setBorderEnabled(true); - } } void LLPanel::setDefaultBtn(std::string_view id) diff --git a/indra/llui/llprogressbar.h b/indra/llui/llprogressbar.h index 0d5d32cf21..7245bbf1cf 100644 --- a/indra/llui/llprogressbar.h +++ b/indra/llui/llprogressbar.h @@ -48,9 +48,9 @@ public: LLProgressBar(const Params&); virtual ~LLProgressBar(); - void setValue(const LLSD& value); + void setValue(const LLSD& value) override; - /*virtual*/ void draw(); + void draw() override; private: F32 mPercentDone; diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h index 4b0f435834..68bf0fd95e 100644 --- a/indra/llui/llresizebar.h +++ b/indra/llui/llresizebar.h @@ -61,7 +61,7 @@ public: void setResizeLimits( S32 min_size, S32 max_size ) { mMinSize = min_size; mMaxSize = max_size; } void setEnableSnapping(bool enable) { mSnappingEnabled = enable; } void setAllowDoubleClickSnapping(bool allow) { mAllowDoubleClickSnapping = allow; } - bool canResize() { return getEnabled() && mMaxSize > mMinSize; } + bool canResize() const { return getEnabled() && mMaxSize > mMinSize; } void setResizeListener(boost::function<void(void*)> listener) {mResizeListener = listener;} void setImagePanel(LLPanel * panelp); LLPanel * getImagePanel() const; diff --git a/indra/llui/llresizehandle.h b/indra/llui/llresizehandle.h index 9cc4123544..caec33405c 100644 --- a/indra/llui/llresizehandle.h +++ b/indra/llui/llresizehandle.h @@ -50,10 +50,10 @@ protected: LLResizeHandle(const LLResizeHandle::Params&); friend class LLUICtrlFactory; public: - virtual void draw(); - virtual bool handleHover(S32 x, S32 y, MASK mask); - virtual bool handleMouseDown(S32 x, S32 y, MASK mask); - virtual bool handleMouseUp(S32 x, S32 y, MASK mask); + void draw() override; + bool handleHover(S32 x, S32 y, MASK mask) override; + bool handleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleMouseUp(S32 x, S32 y, MASK mask) override; void setResizeLimits( S32 min_width, S32 min_height ) { mMinWidth = min_width; mMinHeight = min_height; } @@ -71,8 +71,8 @@ private: const ECorner mCorner; }; -const S32 RESIZE_HANDLE_HEIGHT = 11; -const S32 RESIZE_HANDLE_WIDTH = 11; +constexpr S32 RESIZE_HANDLE_HEIGHT = 11; +constexpr S32 RESIZE_HANDLE_WIDTH = 11; #endif // LL_RESIZEHANDLE_H diff --git a/indra/llui/llrngwriter.h b/indra/llui/llrngwriter.h index 33ec049a1a..2c39472607 100644 --- a/indra/llui/llrngwriter.h +++ b/indra/llui/llrngwriter.h @@ -37,7 +37,7 @@ public: void writeRNG(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); void addDefinition(const std::string& type_name, const LLInitParam::BaseBlock& block); - /*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } + std::string getCurrentElementName() override { return LLStringUtil::null; } LLRNGWriter(); diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 7ef2e54429..a3108d77e8 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -30,6 +30,7 @@ #include "llscrolllistcell.h" #include "llcheckboxctrl.h" +#include "llfontvertexbuffer.h" #include "llui.h" // LLUIImage #include "lluictrlfactory.h" @@ -156,7 +157,7 @@ S32 LLScrollListIcon::getWidth() const } -void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_color) const +void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_color) { if (mIcon) { @@ -236,7 +237,7 @@ S32 LLScrollListBar::getWidth() const } -void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_color) const +void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_color) { S32 bar_width = getWidth() - mLeftPad - mRightPad; S32 left = (S32)(bar_width - bar_width * mRatio); @@ -308,6 +309,19 @@ bool LLScrollListText::needsToolTip() const return mFont->getWidth(mText.getWString().c_str()) > getWidth(); } +void LLScrollListText::setTextWidth(S32 value) +{ + mTextWidth = value; + mFontBuffer.reset(); +} + +void LLScrollListText::setWidth(S32 width) +{ + LLScrollListCell::setWidth(width); + mTextWidth = width; + mFontBuffer.reset(); +} + //virtual bool LLScrollListText::getVisible() const { @@ -341,6 +355,7 @@ void LLScrollListText::setColor(const LLColor4& color) void LLScrollListText::setText(const LLStringExplicit& text) { mText = text; + mFontBuffer.reset(); } void LLScrollListText::setFontStyle(const U8 font_style) @@ -348,6 +363,13 @@ void LLScrollListText::setFontStyle(const U8 font_style) LLFontDescriptor new_desc(mFont->getFontDesc()); new_desc.setStyle(font_style); mFont = LLFontGL::getFont(new_desc); + mFontBuffer.reset(); +} + +void LLScrollListText::setAlignment(LLFontGL::HAlign align) +{ + mFontAlignment = align; + mFontBuffer.reset(); } //virtual @@ -375,7 +397,7 @@ const LLSD LLScrollListText::getAltValue() const } -void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_color) const +void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_color) { LLColor4 display_color; if (mUseColor) @@ -426,17 +448,18 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col start_x = (F32)getWidth() * 0.5f; break; } - mFont->render(mText.getWString(), 0, - start_x, 0.f, - display_color, - mFontAlignment, - LLFontGL::BOTTOM, - 0, - LLFontGL::NO_SHADOW, - string_chars, - getTextWidth(), - &right_x, - true); + mFontBuffer.render(mFont, + mText.getWString(), 0, + start_x, 0.f, + display_color, + mFontAlignment, + LLFontGL::BOTTOM, + 0, + LLFontGL::NO_SHADOW, + string_chars, + getTextWidth(), + &right_x, + true); } // @@ -475,7 +498,7 @@ LLScrollListCheck::~LLScrollListCheck() mCheckBox = NULL; } -void LLScrollListCheck::draw(const LLColor4& color, const LLColor4& highlight_color) const +void LLScrollListCheck::draw(const LLColor4& color, const LLColor4& highlight_color) { mCheckBox->draw(); } @@ -592,7 +615,7 @@ void LLScrollListIconText::setWidth(S32 width) } -void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const +void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) { LLColor4 display_color; if (mUseColor) @@ -650,7 +673,9 @@ void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight start_icon_x = (S32)(center - (((F32)icon_space + mFont->getWidth(mText.getWString().c_str())) * 0.5f)); break; } - mFont->render(mText.getWString(), 0, + mFontBuffer.render( + mFont, + mText.getWString(), 0, start_text_x, 0.f, display_color, mFontAlignment, diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index c5d785ae52..7dded3c0b7 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -29,6 +29,7 @@ #define LLSCROLLLISTCELL_H #include "llfontgl.h" // HAlign +#include "llfontvertexbuffer.h" // HAlign #include "llpointer.h" // LLPointer<> #include "lluistring.h" #include "v4color.h" @@ -96,7 +97,7 @@ public: LLScrollListCell(const LLScrollListCell::Params&); virtual ~LLScrollListCell() {}; - virtual void draw(const LLColor4& color, const LLColor4& highlight_color) const {}; // truncate to given width, if possible + virtual void draw(const LLColor4& color, const LLColor4& highlight_color) {}; // truncate to given width, if possible virtual S32 getWidth() const {return mWidth;} virtual S32 getContentWidth() const { return 0; } virtual S32 getHeight() const { return 0; } @@ -104,7 +105,7 @@ public: virtual const LLSD getAltValue() const; virtual void setValue(const LLSD& value) { } virtual void setAltValue(const LLSD& value) { } - virtual const std::string &getToolTip() const { return mToolTip; } + virtual const std::string& getToolTip() const { return mToolTip; } virtual void setToolTip(const std::string &str) { mToolTip = str; } virtual bool getVisible() const { return true; } virtual void setWidth(S32 width) { mWidth = width; } @@ -127,7 +128,7 @@ class LLScrollListSpacer : public LLScrollListCell public: LLScrollListSpacer(const LLScrollListCell::Params& p) : LLScrollListCell(p) {} /*virtual*/ ~LLScrollListSpacer() {}; - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const {} + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) {} }; /* @@ -139,7 +140,7 @@ public: LLScrollListText(const LLScrollListCell::Params&); /*virtual*/ ~LLScrollListText(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color); /*virtual*/ S32 getContentWidth() const; /*virtual*/ S32 getHeight() const; /*virtual*/ void setValue(const LLSD& value); @@ -155,18 +156,20 @@ public: /*virtual*/ bool needsToolTip() const; S32 getTextWidth() const { return mTextWidth;} - void setTextWidth(S32 value) { mTextWidth = value;} - virtual void setWidth(S32 width) { LLScrollListCell::setWidth(width); mTextWidth = width; } + void setTextWidth(S32 value); + virtual void setWidth(S32 width); void setText(const LLStringExplicit& text); void setFontStyle(const U8 font_style); - void setAlignment(LLFontGL::HAlign align) { mFontAlignment = align; } + void setAlignment(LLFontGL::HAlign align); protected: + LLUIString mText; LLUIString mAltText; S32 mTextWidth; const LLFontGL* mFont; + LLFontVertexBuffer mFontBuffer; LLColor4 mColor; LLColor4 mHighlightColor; U8 mUseColor; @@ -188,7 +191,7 @@ class LLScrollListIcon : public LLScrollListCell public: LLScrollListIcon(const LLScrollListCell::Params& p); /*virtual*/ ~LLScrollListIcon(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color); /*virtual*/ S32 getWidth() const; /*virtual*/ S32 getHeight() const; /*virtual*/ const LLSD getValue() const; @@ -207,7 +210,7 @@ class LLScrollListBar : public LLScrollListCell public: LLScrollListBar(const LLScrollListCell::Params& p); /*virtual*/ ~LLScrollListBar(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color); /*virtual*/ S32 getWidth() const; /*virtual*/ S32 getHeight() const; /*virtual*/ const LLSD getValue() const; @@ -229,7 +232,7 @@ class LLScrollListCheck : public LLScrollListCell public: LLScrollListCheck( const LLScrollListCell::Params&); /*virtual*/ ~LLScrollListCheck(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color); /*virtual*/ S32 getHeight() const { return 0; } /*virtual*/ const LLSD getValue() const; /*virtual*/ void setValue(const LLSD& value); @@ -264,13 +267,11 @@ class LLScrollListIconText : public LLScrollListText public: LLScrollListIconText(const LLScrollListCell::Params& p); /*virtual*/ ~LLScrollListIconText(); - /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const; + /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color); /*virtual*/ const LLSD getValue() const; /*virtual*/ void setValue(const LLSD& value); - - S32 getIconWidth() const; - /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/ + /*virtual*/ void setWidth(S32 width); private: LLPointer<LLUIImage> mIcon; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index e711a6ed1b..245339b107 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -410,10 +410,8 @@ void LLScrollListCtrl::clearRows() LLScrollListItem* LLScrollListCtrl::getFirstSelected() const { - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* item : mItemList) { - LLScrollListItem* item = *iter; if (item->getSelected()) { return item; @@ -425,10 +423,8 @@ LLScrollListItem* LLScrollListCtrl::getFirstSelected() const std::vector<LLScrollListItem*> LLScrollListCtrl::getAllSelected() const { std::vector<LLScrollListItem*> ret; - item_list::const_iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* item : mItemList) { - LLScrollListItem* item = *iter; if (item->getSelected()) { ret.push_back(item); @@ -441,9 +437,8 @@ S32 LLScrollListCtrl::getNumSelected() const { S32 numSelected = 0; - for(item_list::const_iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter) + for (LLScrollListItem* item : mItemList) { - LLScrollListItem* item = *iter; if (item->getSelected()) { ++numSelected; @@ -460,10 +455,8 @@ S32 LLScrollListCtrl::getFirstSelectedIndex() const // make sure sort is up to date before returning an index updateSort(); - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* item : mItemList) { - LLScrollListItem* item = *iter; if (item->getSelected()) { return CurSelectedIndex; @@ -476,29 +469,19 @@ S32 LLScrollListCtrl::getFirstSelectedIndex() const LLScrollListItem* LLScrollListCtrl::getFirstData() const { - if (mItemList.size() == 0) - { - return NULL; - } - return mItemList[0]; + return mItemList.empty() ? NULL : mItemList.front(); } LLScrollListItem* LLScrollListCtrl::getLastData() const { - if (mItemList.size() == 0) - { - return NULL; - } - return mItemList[mItemList.size() - 1]; + return mItemList.empty() ? NULL : mItemList.back(); } std::vector<LLScrollListItem*> LLScrollListCtrl::getAllData() const { std::vector<LLScrollListItem*> ret; - item_list::const_iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* item : mItemList) { - LLScrollListItem* item = *iter; ret.push_back(item); } return ret; @@ -509,20 +492,18 @@ LLScrollListItem* LLScrollListCtrl::getItem(const LLSD& sd) const { std::string string_val = sd.asString(); - item_list::const_iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* item : mItemList) { - LLScrollListItem* item = *iter; // assumes string representation is good enough for comparison if (item->getValue().asString() == string_val) { return item; } } + return NULL; } - void LLScrollListCtrl::reshape( S32 width, S32 height, bool called_from_parent ) { LLUICtrl::reshape( width, height, called_from_parent ); @@ -567,15 +548,16 @@ void LLScrollListCtrl::updateLayout() void LLScrollListCtrl::fitContents(S32 max_width, S32 max_height) { S32 height = llmin( getRequiredRect().getHeight(), max_height ); - if(mPageLines) - height = llmin( mPageLines * mLineHeight + 2*mBorderThickness + (mDisplayColumnHeaders ? mHeadingHeight : 0), height ); + if (mPageLines) + { + height = llmin(mPageLines * mLineHeight + 2 * mBorderThickness + (mDisplayColumnHeaders ? mHeadingHeight : 0), height); + } S32 width = getRect().getWidth(); reshape( width, height ); } - LLRect LLScrollListCtrl::getRequiredRect() { S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0); @@ -627,7 +609,8 @@ bool LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, bool r S32 i = 0; for (LLScrollListCell* cell = item->getColumn(i); i < num_cols; cell = item->getColumn(++i)) { - if (i >= (S32)mColumnsIndexed.size()) break; + if (i >= (S32)mColumnsIndexed.size()) + break; cell->setWidth(mColumnsIndexed[i]->getWidth()); } @@ -650,23 +633,21 @@ S32 LLScrollListCtrl::calcMaxContentWidth() S32 max_item_width = 0; - ordered_columns_t::iterator column_itor; - for (column_itor = mColumnsIndexed.begin(); column_itor != mColumnsIndexed.end(); ++column_itor) + for (LLScrollListColumn* column : mColumnsIndexed) { - LLScrollListColumn* column = *column_itor; - if (!column) continue; + if (!column) + continue; if (mColumnWidthsDirty) { // update max content width for this column, by looking at all items column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel.getWString().c_str()) + mColumnPadding + HEADING_TEXT_PADDING : 0; - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* item : mItemList) { - LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex); - if (!cellp) continue; - - column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth); + if (LLScrollListCell* cellp = item->getColumn(column->mIndex)) + { + column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth); + } } } max_item_width += column->mMaxContentWidth; @@ -683,7 +664,8 @@ bool LLScrollListCtrl::updateColumnWidths() for (column_itor = mColumnsIndexed.begin(); column_itor != mColumnsIndexed.end(); ++column_itor) { LLScrollListColumn* column = *column_itor; - if (!column) continue; + if (!column) + continue; // update column width S32 new_width = 0; @@ -737,7 +719,6 @@ void LLScrollListCtrl::updateLineHeightInsert(LLScrollListItem* itemp) } } - void LLScrollListCtrl::updateColumns(bool force_update) { if (!mColumnsDirty && !force_update) @@ -810,7 +791,8 @@ void LLScrollListCtrl::updateColumns(bool force_update) S32 i = 0; for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) { - if (i >= (S32)mColumnsIndexed.size()) break; + if (i >= (S32)mColumnsIndexed.size()) + break; cell->setWidth(mColumnsIndexed[i]->getWidth()); } @@ -837,8 +819,8 @@ void LLScrollListCtrl::setHeadingHeight(S32 heading_height) mHeadingHeight = heading_height; updateLayout(); - } + void LLScrollListCtrl::setPageLines(S32 new_page_lines) { mPageLines = new_page_lines; @@ -880,6 +862,7 @@ bool LLScrollListCtrl::selectFirstItem() } first_item = false; } + if (mCommitOnSelectionChange) { commitIfChanged(); @@ -889,13 +872,13 @@ bool LLScrollListCtrl::selectFirstItem() // Deselects all other items // virtual -bool LLScrollListCtrl::selectNthItem( S32 target_index ) +bool LLScrollListCtrl::selectNthItem(S32 target_index) { return selectItemRange(target_index, target_index); } // virtual -bool LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index ) +bool LLScrollListCtrl::selectItemRange(S32 first_index, S32 last_index) { if (mItemList.empty()) { @@ -905,28 +888,24 @@ bool LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index ) // make sure sort is up to date updateSort(); - S32 listlen = (S32)mItemList.size(); - first_index = llclamp(first_index, 0, listlen-1); - - if (last_index < 0) - last_index = listlen-1; - else - last_index = llclamp(last_index, first_index, listlen-1); + S32 bottom = (S32)mItemList.size() - 1; + first_index = llclamp(first_index, 0, bottom); + last_index = last_index < 0 ? bottom : llclamp(last_index, first_index, bottom); bool success = false; S32 index = 0; for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); ) { LLScrollListItem *itemp = *iter; - if(!itemp) + if (!itemp) { iter = mItemList.erase(iter); - continue ; + continue; } - if( index >= first_index && index <= last_index ) + if (index >= first_index && index <= last_index) { - if( itemp->getEnabled() ) + if (itemp->getEnabled()) { // TODO: support range selection for cells selectItem(itemp, -1, false); @@ -1173,7 +1152,6 @@ void LLScrollListCtrl::selectPrevItem( bool extend_selection) mSearchString.clear(); } - void LLScrollListCtrl::selectNextItem( bool extend_selection) { LLScrollListItem* next_item = NULL; @@ -1217,8 +1195,6 @@ void LLScrollListCtrl::selectNextItem( bool extend_selection) mSearchString.clear(); } - - void LLScrollListCtrl::deselectAllItems(bool no_commit_on_change) { item_list::iterator iter; @@ -1290,16 +1266,14 @@ LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, boo LLStringUtil::toLower(target_text); } - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* item : mItemList) { - LLScrollListItem* item = *iter; std::string item_text = item->getColumn(column)->getValue().asString(); // Only select enabled items with matching names if (!case_sensitive) { LLStringUtil::toLower(item_text); } - if(item_text == target_text) + if (item_text == target_text) { return item; } @@ -1307,6 +1281,15 @@ LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, boo return NULL; } +LLScrollListItem* LLScrollListCtrl::getItemByIndex(S32 index) +{ + if (index >= 0 && index < (S32)mItemList.size()) + { + return mItemList[index]; + } + + return NULL; +} bool LLScrollListCtrl::selectItemByPrefix(const std::string& target, bool case_sensitive, S32 column) { @@ -1467,7 +1450,7 @@ U32 LLScrollListCtrl::searchItems(const LLWString& substring, bool case_sensitiv return found; } -const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const +std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const { LLScrollListItem* item; @@ -1511,7 +1494,10 @@ bool LLScrollListCtrl::setSelectedByValue(const LLSD& value, bool selected) { bool found = false; - if (selected && !mAllowMultipleSelection) deselectAllItems(true); + if (selected && !mAllowMultipleSelection) + { + deselectAllItems(true); + } item_list::iterator iter; for (iter = mItemList.begin(); iter != mItemList.end(); iter++) @@ -2638,9 +2624,7 @@ bool LLScrollListCtrl::isRepeatedChars(const LLWString& string) const void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, bool select_single_item) { - if (!itemp) return; - - if (!itemp->getSelected()) + if (itemp && !itemp->getSelected()) { if (mLastSelected) { @@ -2674,9 +2658,7 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, bool select void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp) { - if (!itemp) return; - - if (itemp->getSelected()) + if (itemp && itemp->getSelected()) { if (mLastSelected == itemp) { @@ -2882,7 +2864,7 @@ void LLScrollListCtrl::updateStaticColumnWidth(LLScrollListColumn* col, S32 new_ // LLEditMenuHandler functions // virtual -void LLScrollListCtrl::copy() +void LLScrollListCtrl::copy() { std::string buffer; @@ -2896,26 +2878,26 @@ void LLScrollListCtrl::copy() } // virtual -bool LLScrollListCtrl::canCopy() const +bool LLScrollListCtrl::canCopy() const { return (getFirstSelected() != NULL); } // virtual -void LLScrollListCtrl::cut() +void LLScrollListCtrl::cut() { copy(); doDelete(); } // virtual -bool LLScrollListCtrl::canCut() const +bool LLScrollListCtrl::canCut() const { return canCopy() && canDoDelete(); } // virtual -void LLScrollListCtrl::selectAll() +void LLScrollListCtrl::selectAll() { // Deselects all other items item_list::iterator iter; @@ -2935,13 +2917,13 @@ void LLScrollListCtrl::selectAll() } // virtual -bool LLScrollListCtrl::canSelectAll() const +bool LLScrollListCtrl::canSelectAll() const { return getCanSelect() && mAllowMultipleSelection && !(mMaxSelectable > 0 && mItemList.size() > mMaxSelectable); } // virtual -void LLScrollListCtrl::deselect() +void LLScrollListCtrl::deselect() { deselectAllItems(); } @@ -3412,7 +3394,7 @@ bool LLScrollListCtrl::highlightMatchingItems(const std::string& filter_str) bool res = false; - setHighlightedColor(LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red)); + setHighlightedColor(LLUIColorTable::instance().getColor("SearchableControlHighlightBgColor", LLColor4::red4)); std::string filter_str_lc(filter_str); LLStringUtil::toLower(filter_str_lc); diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 1f9f26e08b..1f04100306 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -165,7 +165,6 @@ public: void deleteAllItems() { clearRows(); } // Sets an array of column descriptors - void setColumnHeadings(const LLSD& headings); void sortByColumnIndex(U32 column, bool ascending); // LLCtrlListInterface functions @@ -260,11 +259,12 @@ public: // one of which can be selected at a time. virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD()); - bool selectItemByLabel( const std::string& item, bool case_sensitive = true, S32 column = 0 ); // false if item not found + bool selectItemByLabel(const std::string& item, bool case_sensitive = true, S32 column = 0); // false if item not found bool selectItemByPrefix(const std::string& target, bool case_sensitive = true, S32 column = -1); bool selectItemByPrefix(const LLWString& target, bool case_sensitive = true, S32 column = -1); - LLScrollListItem* getItemByLabel( const std::string& item, bool case_sensitive = true, S32 column = 0 ); - const std::string getSelectedItemLabel(S32 column = 0) const; + LLScrollListItem* getItemByLabel(const std::string& item, bool case_sensitive = true, S32 column = 0); + LLScrollListItem* getItemByIndex(S32 index); + std::string getSelectedItemLabel(S32 column = 0) const; LLSD getSelectedValue(); // If multi select is on, select all element that include substring, @@ -317,7 +317,7 @@ public: void setAllowKeyboardMovement(bool b) { mAllowKeyboardMovement = b; } void setMaxSelectable(U32 max_selected) { mMaxSelectable = max_selected; } - S32 getMaxSelectable() { return mMaxSelectable; } + S32 getMaxSelectable() const { return mMaxSelectable; } virtual S32 getScrollPos() const; @@ -333,7 +333,7 @@ public: // support right-click context menus for avatar/group lists enum ContextMenuType { MENU_NONE, MENU_AVATAR, MENU_GROUP }; void setContextMenu(const ContextMenuType &menu) { mContextMenuType = menu; } - ContextMenuType getContextMenuType() { return mContextMenuType; } + ContextMenuType getContextMenuType() const { return mContextMenuType; } // Overridden from LLView /*virtual*/ void draw(); @@ -361,7 +361,6 @@ public: virtual void fitContents(S32 max_width, S32 max_height); virtual LLRect getRequiredRect(); - static bool rowPreceeds(LLScrollListItem *new_row, LLScrollListItem *test_row); LLRect getItemListRect() { return mItemListRect; } @@ -383,7 +382,6 @@ public: * then display all items. */ void setPageLines(S32 page_lines ); - void setCollapseEmptyColumns(bool collapse); LLScrollListItem* hitItem(S32 x,S32 y); virtual void scrollToShowSelected(); @@ -400,7 +398,7 @@ public: void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; } void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); - S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } + S32 getTotalStaticColumnWidth() const { return mTotalStaticColumnWidth; } std::string getSortColumnName(); bool getSortAscending() { return mSortColumns.empty() ? true : mSortColumns.back().second; } @@ -559,6 +557,8 @@ private: sort_signal_t* mSortCallback; is_friend_signal_t* mIsFriendSignal; + + friend class LLComboBox; }; // end class LLScrollListCtrl #endif // LL_SCROLLLISTCTRL_H diff --git a/indra/llui/llsearchablecontrol.h b/indra/llui/llsearchablecontrol.h index 119852b763..bae85fe9a5 100644 --- a/indra/llui/llsearchablecontrol.h +++ b/indra/llui/llsearchablecontrol.h @@ -43,9 +43,15 @@ namespace ll virtual ~SearchableControl() { } - const LLColor4& getHighlightColor( ) const + const LLColor4& getHighlightBgColor( ) const { - static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red); + static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightBgColor", LLColor4::red4); + return highlight_color.get(); + } + + const LLColor4& getHighlightFontColor() const + { + static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightFontColor", LLColor4::red4); return highlight_color.get(); } diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index 311377a61f..23ce8fd955 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -132,7 +132,6 @@ public: static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata); static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); - static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); protected: virtual std::string _getSearchText() const diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h index 58b38dc630..4ba8c97c63 100644 --- a/indra/llui/llspinctrl.h +++ b/indra/llui/llspinctrl.h @@ -94,7 +94,6 @@ public: void onEditorCommit(const LLSD& data); static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); static void onEditorLostFocus(LLFocusableElement* caller, void *userdata); - static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); void onUpBtn(const LLSD& data); void onDownBtn(const LLSD& data); diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index 2693243eb1..62c0401869 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -460,7 +460,7 @@ void LLStatBar::draw() max_value = 0.f; gGL.color4f(1.f, 0.f, 0.f, 1.f); - gGL.begin( LLRender::QUADS ); + gGL.begin(LLRender::TRIANGLES); const S32 max_frame = llmin(num_frames, num_values); U32 num_samples = 0; for (S32 i = 1; i <= max_frame; i++) @@ -498,6 +498,9 @@ void LLStatBar::draw() gGL.vertex2f((F32)bar_rect.mRight - offset, max); gGL.vertex2f((F32)bar_rect.mRight - offset, min); gGL.vertex2f((F32)bar_rect.mRight - offset - 1, min); + + gGL.vertex2f((F32)bar_rect.mRight - offset, max); + gGL.vertex2f((F32)bar_rect.mRight - offset - 1, min); gGL.vertex2f((F32)bar_rect.mRight - offset - 1, max); } else @@ -505,7 +508,10 @@ void LLStatBar::draw() gGL.vertex2f(min, (F32)bar_rect.mBottom + offset + 1); gGL.vertex2f(min, (F32)bar_rect.mBottom + offset); gGL.vertex2f(max, (F32)bar_rect.mBottom + offset); - gGL.vertex2f(max, (F32)bar_rect.mBottom + offset + 1 ); + + gGL.vertex2f(min, (F32)bar_rect.mBottom + offset + 1); + gGL.vertex2f(max, (F32)bar_rect.mBottom + offset); + gGL.vertex2f(max, (F32)bar_rect.mBottom + offset + 1); } } gGL.end(); diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h index c36a138566..bbbf0b3a19 100644 --- a/indra/llui/llstatbar.h +++ b/indra/llui/llstatbar.h @@ -67,7 +67,7 @@ public: void setStat(const std::string& stat_name); void setRange(F32 bar_min, F32 bar_max); - void getRange(F32& bar_min, F32& bar_max) { bar_min = mTargetMinBar; bar_max = mTargetMaxBar; } + void getRange(F32& bar_min, F32& bar_max) const { bar_min = mTargetMinBar; bar_max = mTargetMaxBar; } /*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options. diff --git a/indra/llui/llstatgraph.cpp b/indra/llui/llstatgraph.cpp index d97051247e..0af717d447 100644 --- a/indra/llui/llstatgraph.cpp +++ b/indra/llui/llstatgraph.cpp @@ -36,7 +36,6 @@ #include "llglheaders.h" #include "lltracerecording.h" #include "lltracethreadrecorder.h" -//#include "llviewercontrol.h" /////////////////////////////////////////////////////////////////////////////////// diff --git a/indra/llui/llstatgraph.h b/indra/llui/llstatgraph.h index c254821870..6d9e3d1064 100644 --- a/indra/llui/llstatgraph.h +++ b/indra/llui/llstatgraph.h @@ -99,9 +99,7 @@ public: void setMin(const F32 min); void setMax(const F32 max); - virtual void draw(); - - /*virtual*/ void setValue(const LLSD& value); + void draw() override; private: LLTrace::StatType<LLTrace::CountAccumulator>* mNewStatFloatp; @@ -133,9 +131,6 @@ private: }; typedef std::vector<Threshold> threshold_vec_t; threshold_vec_t mThresholds; - //S32 mNumThresholds; - //F32 mThresholds[4]; - //LLColor4 mThresholdColors[4]; }; #endif // LL_LLSTATGRAPH_H diff --git a/indra/llui/llstatview.h b/indra/llui/llstatview.h index b5187f886d..a396773057 100644 --- a/indra/llui/llstatview.h +++ b/indra/llui/llstatview.h @@ -29,7 +29,6 @@ #include "llstatbar.h" #include "llcontainerview.h" -#include <vector> class LLStatBar; diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp index df4b0ef6a0..7a0e620d61 100644 --- a/indra/llui/llstyle.cpp +++ b/indra/llui/llstyle.cpp @@ -38,11 +38,13 @@ LLStyle::Params::Params() color("color", LLColor4::black), readonly_color("readonly_color", LLColor4::black), selected_color("selected_color", LLColor4::black), + highlight_bg_color("highlight_bg_color", LLColor4::green), alpha("alpha", 1.f), - font("font", LLFontGL::getFontMonospace()), + font("font", LLStyle::getDefaultFont()), image("image"), link_href("href"), - is_link("is_link") + is_link("is_link"), + draw_highlight_bg("draw_highlight_bg", false) {} @@ -51,12 +53,14 @@ LLStyle::LLStyle(const LLStyle::Params& p) mColor(p.color), mReadOnlyColor(p.readonly_color), mSelectedColor(p.selected_color), + mHighlightBgColor(p.highlight_bg_color), mFont(p.font()), mLink(p.link_href), mIsLink(p.is_link.isProvided() ? p.is_link : !p.link_href().empty()), mDropShadow(p.drop_shadow), mImagep(p.image()), - mAlpha(p.alpha) + mAlpha(p.alpha), + mDrawHighlightBg(p.draw_highlight_bg) {} void LLStyle::setFont(const LLFontGL* font) @@ -70,6 +74,11 @@ const LLFontGL* LLStyle::getFont() const return mFont; } +const LLFontGL* LLStyle::getDefaultFont() +{ + return LLFontGL::getFontMonospace(); +} + void LLStyle::setLinkHREF(const std::string& href) { mLink = href; diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h index e506895de5..71c3f88109 100644 --- a/indra/llui/llstyle.h +++ b/indra/llui/llstyle.h @@ -43,15 +43,25 @@ public: Optional<LLFontGL::ShadowType> drop_shadow; Optional<LLUIColor> color, readonly_color, - selected_color; + selected_color, + highlight_bg_color; Optional<F32> alpha; Optional<const LLFontGL*> font; Optional<LLUIImage*> image; Optional<std::string> link_href; Optional<bool> is_link; + Optional<bool> draw_highlight_bg; Params(); }; LLStyle(const Params& p = Params()); + + enum EUnderlineLink + { + UNDERLINE_ALWAYS = 0, + UNDERLINE_ON_HOVER, + UNDERLINE_NEVER + }; + public: const LLUIColor& getColor() const { return mColor; } void setColor(const LLUIColor &color) { mColor = color; } @@ -72,6 +82,7 @@ public: void setFont(const LLFontGL* font); const LLFontGL* getFont() const; + static const LLFontGL* getDefaultFont(); const std::string& getLinkHREF() const { return mLink; } void setLinkHREF(const std::string& href); @@ -83,6 +94,9 @@ public: bool isImage() const { return mImagep.notNull(); } + bool getDrawHighlightBg() const { return mDrawHighlightBg; } + const LLUIColor& getHighlightBgColor() const { return mHighlightBgColor; } + bool operator==(const LLStyle &rhs) const { return @@ -90,11 +104,13 @@ public: && mColor == rhs.mColor && mReadOnlyColor == rhs.mReadOnlyColor && mSelectedColor == rhs.mSelectedColor + && mHighlightBgColor == rhs.mHighlightBgColor && mFont == rhs.mFont && mLink == rhs.mLink && mImagep == rhs.mImagep && mDropShadow == rhs.mDropShadow - && mAlpha == rhs.mAlpha; + && mAlpha == rhs.mAlpha + && mDrawHighlightBg == rhs.mDrawHighlightBg; } bool operator!=(const LLStyle& rhs) const { return !(*this == rhs); } @@ -111,11 +127,13 @@ private: LLUIColor mColor; LLUIColor mReadOnlyColor; LLUIColor mSelectedColor; + LLUIColor mHighlightBgColor; const LLFontGL* mFont; LLPointer<LLUIImage> mImagep; F32 mAlpha; bool mVisible; bool mIsLink; + bool mDrawHighlightBg; }; typedef LLPointer<LLStyle> LLStyleSP; diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 595ab0bd2b..5e0985c79c 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1370,17 +1370,17 @@ LLPanel* LLTabContainer::getCurrentPanel() return NULL; } -S32 LLTabContainer::getCurrentPanelIndex() +S32 LLTabContainer::getCurrentPanelIndex() const { return mCurrentTabIdx; } -S32 LLTabContainer::getTabCount() +S32 LLTabContainer::getTabCount() const { return static_cast<S32>(mTabList.size()); } -LLPanel* LLTabContainer::getPanelByIndex(S32 index) +LLPanel* LLTabContainer::getPanelByIndex(S32 index) const { if (index >= 0 && index < (S32)mTabList.size()) { @@ -1389,7 +1389,7 @@ LLPanel* LLTabContainer::getPanelByIndex(S32 index) return NULL; } -S32 LLTabContainer::getIndexForPanel(LLPanel* panel) +S32 LLTabContainer::getIndexForPanel(LLPanel* panel) const { for (S32 index = 0; index < (S32)mTabList.size(); index++) { @@ -1401,7 +1401,7 @@ S32 LLTabContainer::getIndexForPanel(LLPanel* panel) return -1; } -S32 LLTabContainer::getPanelIndexByTitle(std::string_view title) +S32 LLTabContainer::getPanelIndexByTitle(std::string_view title) const { for (S32 index = 0 ; index < (S32)mTabList.size(); index++) { diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 40f272ffa8..4ac7e73d25 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -182,15 +182,15 @@ public: void removeTabPanel( LLPanel* child ); void lockTabs(S32 num_tabs = 0); void unlockTabs(); - S32 getNumLockedTabs() { return mLockedTabCount; } + S32 getNumLockedTabs() const { return mLockedTabCount; } void enableTabButton(S32 which, bool enable); void deleteAllTabs(); LLPanel* getCurrentPanel(); - S32 getCurrentPanelIndex(); - S32 getTabCount(); - LLPanel* getPanelByIndex(S32 index); - S32 getIndexForPanel(LLPanel* panel); - S32 getPanelIndexByTitle(std::string_view title); + S32 getCurrentPanelIndex() const; + S32 getTabCount() const; + LLPanel* getPanelByIndex(S32 index) const; + S32 getIndexForPanel(LLPanel* panel) const; + S32 getPanelIndexByTitle(std::string_view title) const; LLPanel* getPanelByName(std::string_view name); S32 getTotalTabWidth() const; void setCurrentTabName(const std::string& name); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 0aebf7543c..778b253c3c 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -460,6 +460,62 @@ std::vector<LLRect> LLTextBase::getSelectionRects() return selection_rects; } +std::vector<std::pair<LLRect, LLUIColor>> LLTextBase::getHighlightedBgRects() +{ + std::vector<std::pair<LLRect, LLUIColor>> highlight_rects; + + LLRect content_display_rect = getVisibleDocumentRect(); + + // binary search for line that starts before top of visible buffer + line_list_t::const_iterator line_iter = + std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom()); + line_list_t::const_iterator end_iter = + std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top()); + + for (; line_iter != end_iter; ++line_iter) + { + segment_set_t::iterator segment_iter; + S32 segment_offset; + getSegmentAndOffset(line_iter->mDocIndexStart, &segment_iter, &segment_offset); + + // Use F32 otherwise a string of multiple segments + // will accumulate a large error + F32 left_precise = (F32)line_iter->mRect.mLeft; + F32 right_precise = (F32)line_iter->mRect.mLeft; + + for (; segment_iter != mSegments.end(); ++segment_iter, segment_offset = 0) + { + LLTextSegmentPtr segmentp = *segment_iter; + + S32 segment_line_start = segmentp->getStart() + segment_offset; + S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd); + + if (segment_line_start > segment_line_end) + break; + + F32 segment_width = 0; + S32 segment_height = 0; + + S32 num_chars = segment_line_end - segment_line_start; + segmentp->getDimensionsF32(segment_offset, num_chars, segment_width, segment_height); + right_precise += segment_width; + + if (segmentp->getStyle()->getDrawHighlightBg()) + { + LLRect selection_rect; + selection_rect.mLeft = (S32)left_precise; + selection_rect.mRight = (S32)right_precise; + selection_rect.mBottom = line_iter->mRect.mBottom; + selection_rect.mTop = line_iter->mRect.mTop; + + highlight_rects.push_back(std::pair(selection_rect, segmentp->getStyle()->getHighlightBgColor())); + } + left_precise += segment_width; + } + } + return highlight_rects; +} + // Draws the black box behind the selected text void LLTextBase::drawSelectionBackground() { @@ -529,6 +585,71 @@ void LLTextBase::drawSelectionBackground() } } +void LLTextBase::drawHighlightedBackground() +{ + if (!mLineInfoList.empty()) + { + std::vector<std::pair<LLRect, LLUIColor>> highlight_rects = getHighlightedBgRects(); + + if (highlight_rects.empty()) + return; + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLRect content_display_rect = getVisibleDocumentRect(); + + for (std::vector<std::pair<LLRect, LLUIColor>>::iterator rect_it = highlight_rects.begin(); + rect_it != highlight_rects.end(); ++rect_it) + { + LLRect selection_rect = rect_it->first; + const LLColor4& color = rect_it->second; + if (mScroller) + { + // If scroller is On content_display_rect has correct rect and safe to use as is + // Note: we might need to account for border + selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom); + } + else + { + // If scroller is Off content_display_rect will have rect from document, adjusted to text width, heigh and position + // and we have to acount for offset depending on position + S32 v_delta = 0; + S32 h_delta = 0; + switch (mVAlign) + { + case LLFontGL::TOP: + v_delta = mVisibleTextRect.mTop - content_display_rect.mTop - mVPad; + break; + case LLFontGL::VCENTER: + v_delta = (llmax(mVisibleTextRect.getHeight() - content_display_rect.mTop, -content_display_rect.mBottom) + (mVisibleTextRect.mBottom - content_display_rect.mBottom)) / 2; + break; + case LLFontGL::BOTTOM: + v_delta = mVisibleTextRect.mBottom - content_display_rect.mBottom; + break; + default: + break; + } + switch (mHAlign) + { + case LLFontGL::LEFT: + h_delta = mVisibleTextRect.mLeft - content_display_rect.mLeft + mHPad; + break; + case LLFontGL::HCENTER: + h_delta = (llmax(mVisibleTextRect.getWidth() - content_display_rect.mLeft, -content_display_rect.mRight) + (mVisibleTextRect.mRight - content_display_rect.mRight)) / 2; + break; + case LLFontGL::RIGHT: + h_delta = mVisibleTextRect.mRight - content_display_rect.mRight; + break; + default: + break; + } + selection_rect.translate(h_delta, v_delta); + } + gl_rect_2d(selection_rect, color); + } + } +} + void LLTextBase::drawCursor() { F32 alpha = getDrawContext().mAlpha; @@ -948,7 +1069,6 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) { - beforeValueChange(); segment_set_t::iterator seg_iter = getSegIterContaining(pos); while(seg_iter != mSegments.end()) @@ -1325,6 +1445,7 @@ void LLTextBase::reshape(S32 width, S32 height, bool called_from_parent) //virtual void LLTextBase::draw() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // reflow if needed, on demand reflow(); @@ -1378,7 +1499,7 @@ void LLTextBase::draw() // Draw highlighted if needed if( ll::ui::SearchableControl::getHighlighted() ) { - const LLColor4& bg_color = ll::ui::SearchableControl::getHighlightColor(); + const LLColor4& bg_color = ll::ui::SearchableControl::getHighlightBgColor(); LLRect bg_rect = mVisibleTextRect; if( mScroller ) bg_rect.intersectWith( text_rect ); @@ -1399,6 +1520,7 @@ void LLTextBase::draw() drawChild(mDocumentView); } + drawHighlightedBackground(); drawSelectionBackground(); drawText(); drawCursor(); @@ -1438,7 +1560,8 @@ void LLTextBase::onVisibilityChange( bool new_visibility ) //virtual void LLTextBase::setValue(const LLSD& value ) { - setText(value.asString()); + static const LLStyle::Params input_params = LLStyle::Params(); + setText(value.asString(), input_params); } //virtual @@ -2199,20 +2322,20 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name) } -void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params) +void LLTextBase::appendTextImpl(const std::string& new_text, const LLStyle::Params& input_params, bool force_slurl) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; LLStyle::Params style_params(getStyleParams()); style_params.overwriteFrom(input_params); S32 part = (S32)LLTextParser::WHOLE; - if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). + if ((mParseHTML || force_slurl) && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). { S32 start=0,end=0; LLUrlMatch match; std::string text = new_text; while (LLUrlRegistry::instance().findUrl(text, match, - boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons)) + boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons, force_slurl)) { start = match.getStart(); end = match.getEnd()+1; @@ -2244,7 +2367,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para } // output the styled Url - appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly()); + appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.getUnderline()); bool tooltip_required = !match.getTooltip().empty(); // set the tooltip for the Url label @@ -2259,7 +2382,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para { link_params.color = LLColor4::grey; link_params.readonly_color = LLColor4::grey; - appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly()); + appendAndHighlightTextImpl(label, part, link_params, match.getUnderline()); // set the tooltip for the query part of url if (tooltip_required) @@ -2368,6 +2491,34 @@ S32 LLTextBase::removeFirstLine() return 0; } +// virtual +void LLTextBase::copyContents(const LLTextBase* source) +{ + llassert(source); + if (!source) + return; + + beforeValueChange(); + deselect(); + + mSegments.clear(); + for (const LLTextSegmentPtr& segp : source->mSegments) + { + mSegments.emplace(segp->clone(*this)); + } + + mLineInfoList.clear(); + for (const line_info& li : mLineInfoList) + { + mLineInfoList.push_back(line_info(li)); + } + + getViewModel()->setDisplay(source->getViewModel()->getDisplay()); + + onValueChange(0, getLength()); + needsReflow(); +} + void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params) { segment_vec_t segments; @@ -2399,7 +2550,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, bool underline_on_hover_only) +void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, e_underline underline_link) { // Save old state S32 selection_start = mSelectionStart; @@ -2429,7 +2580,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig S32 cur_length = getLength(); LLStyleConstSP sp(new LLStyle(highlight_params)); LLTextSegmentPtr segmentp; - if (underline_on_hover_only || mSkipLinkUnderline) + if ((underline_link == e_underline::UNDERLINE_ON_HOVER) || mSkipLinkUnderline) { highlight_params.font.style("NORMAL"); LLStyleConstSP normal_sp(new LLStyle(highlight_params)); @@ -2453,7 +2604,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig S32 segment_start = old_length; S32 segment_end = old_length + static_cast<S32>(wide_text.size()); LLStyleConstSP sp(new LLStyle(style_params)); - if (underline_on_hover_only || mSkipLinkUnderline) + if ((underline_link == e_underline::UNDERLINE_ON_HOVER) || mSkipLinkUnderline) { LLStyle::Params normal_style_params(style_params); normal_style_params.font.style("NORMAL"); @@ -2487,7 +2638,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, bool underline_on_hover_only) +void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, e_underline underline_link) { if (new_text.empty()) { @@ -2502,7 +2653,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, underline_on_hover_only); + appendAndHighlightTextImpl(str, highlight_part, style_params, underline_link); } appendLineBreakSegment(style_params); start = pos+1; @@ -2510,7 +2661,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, underline_on_hover_only); + appendAndHighlightTextImpl(str, highlight_part, style_params, underline_link); } @@ -2586,6 +2737,11 @@ const LLWString& LLTextBase::getWText() const return getViewModel()->getDisplay(); } +S32 LLTextBase::getTextGeneration() const +{ + return getViewModel()->getDisplayGeneration(); +} + // If round is true, if the position is on the right half of a character, the cursor // will be put to its right. If round is false, the cursor will always be put to the // character's left. @@ -3228,6 +3384,24 @@ boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_bloc LLTextSegment::~LLTextSegment() {} +// static +LLStyleSP LLTextSegment::cloneStyle(LLTextBase& target, const LLStyle* source) +{ + // Take most params from target + LLStyle::Params params = target.getStyleParams(); + LLStyle* style = new LLStyle(params); + + // Take some params from source + style->setLinkHREF(source->getLinkHREF()); + if (source->isImage()) + { + style->setImage(source->getImage()->getName()); + } + + return style; +} + + bool LLTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; height = 0; return false; } bool LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { @@ -3280,9 +3454,11 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e : LLTextSegment(start, end), mStyle( style ), mToken(NULL), - mEditor(editor) + mEditor(editor), + mLastGeneration(-1) { mFontHeight = mStyle->getFont()->getLineHeight(); + mCanEdit = !mStyle->getDrawHighlightBg(); LLUIImagePtr image = mStyle->getImage(); if (image.notNull()) @@ -3294,7 +3470,8 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e LLNormalTextSegment::LLNormalTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible) : LLTextSegment(start, end), mToken(NULL), - mEditor(editor) + mEditor(editor), + mLastGeneration(-1) { mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color)); @@ -3313,25 +3490,41 @@ F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selec { return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect); } + else + { + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); + } return draw_rect.mLeft; } // Draws a single text segment, reversing the color for selection if needed. F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRectf rect) { - F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha; - - const LLWString &text = getWText(); - F32 right_x = rect.mLeft; if (!mStyle->isVisible()) { return right_x; } - const LLFontGL* font = mStyle->getFont(); + F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha; + + const LLWString& text = getWText(); + S32 text_gen = mEditor.getTextGeneration(); + if (text_gen != mLastGeneration) + { + mLastGeneration = text_gen; + + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); + } + + const LLFontGL* font = mStyle->getFont(); LLColor4 color = (mEditor.getReadOnly() ? mStyle->getReadOnlyColor() : mStyle->getColor()) % (alpha * mStyle->getAlpha()); + bool use_font_buffers = useFontBuffers(); if( selection_start > seg_start ) { @@ -3339,16 +3532,40 @@ 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, - color, - LLFontGL::LEFT, mEditor.mTextVAlign, - LLFontGL::NORMAL, - mStyle->getShadowType(), - length, - &right_x, - mEditor.getUseEllipses(), - mEditor.getUseColor()); + if (use_font_buffers) + { + mFontBufferPreSelection.render( + font, + text, start, + rect, + color, + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + } + else + { + // Font buffer doesn't do well with changes and huge notecard with a bunch + // of segments will see a lot of buffer updates, so instead use derect + // rendering to cache. + // Todo: instead of mLastGeneration make buffer invalidation more fine grained + // like string hash of a given segment. + font->render( + text, start, + rect, + color, + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + } } rect.mLeft = right_x; @@ -3359,16 +3576,35 @@ 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, - mStyle->getSelectedColor().get(), - LLFontGL::LEFT, mEditor.mTextVAlign, - LLFontGL::NORMAL, - LLFontGL::NO_SHADOW, - length, - &right_x, - mEditor.getUseEllipses(), - mEditor.getUseColor()); + if (use_font_buffers) + { + mFontBufferSelection.render( + font, + text, start, + rect, + mStyle->getSelectedColor().get(), + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + LLFontGL::NO_SHADOW, + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + } + else + { + font->render( + text, start, + rect, + mStyle->getSelectedColor().get(), + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + LLFontGL::NO_SHADOW, + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + } } rect.mLeft = right_x; if( selection_end < seg_end ) @@ -3377,16 +3613,36 @@ 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, - color, - LLFontGL::LEFT, mEditor.mTextVAlign, - LLFontGL::NORMAL, - mStyle->getShadowType(), - length, - &right_x, - mEditor.getUseEllipses(), - mEditor.getUseColor()); + if (use_font_buffers) + { + mFontBufferPostSelection.render( + font, + text, start, + rect, + color, + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + } + else + { + font->render( + text, start, + rect, + color, + LLFontGL::LEFT, mEditor.mTextVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses(), + mEditor.getUseColor()); + + } } return right_x; } @@ -3488,6 +3744,13 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip) mTooltip = tooltip; } +// virtual +LLTextSegmentPtr LLNormalTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP sp(cloneStyle(target, mStyle)); + return new LLNormalTextSegment(sp, mStart, mEnd, target); +} + bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { height = 0; @@ -3573,6 +3836,15 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin return num_chars; } +void LLNormalTextSegment::updateLayout(const class LLTextBase& editor) +{ + LLTextSegment::updateLayout(editor); + + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); +} + void LLNormalTextSegment::dump() const { LL_INFOS() << "Segment [" << @@ -3606,6 +3878,13 @@ LLLabelTextSegment::LLLabelTextSegment( const LLUIColor& color, S32 start, S32 e { } +// virtual +LLTextSegmentPtr LLLabelTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP sp(cloneStyle(target, mStyle)); + return new LLLabelTextSegment(sp, mStart, mEnd, target); +} + /*virtual*/ const LLWString& LLLabelTextSegment::getWText() const { @@ -3630,6 +3909,13 @@ LLEmojiTextSegment::LLEmojiTextSegment(const LLUIColor& color, S32 start, S32 en { } +// virtual +LLTextSegmentPtr LLEmojiTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP sp(cloneStyle(target, mStyle)); + return new LLEmojiTextSegment(sp, mStart, mEnd, target); +} + bool LLEmojiTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { if (mTooltip.empty()) @@ -3653,6 +3939,14 @@ LLOnHoverChangeableTextSegment::LLOnHoverChangeableTextSegment( LLStyleConstSP s mHoveredStyle(style), mNormalStyle(normal_style){} +// virtual +LLTextSegmentPtr LLOnHoverChangeableTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP hsp(cloneStyle(target, mHoveredStyle)); + LLStyleConstSP nsp(cloneStyle(target, mNormalStyle)); + return new LLOnHoverChangeableTextSegment(hsp, nsp, mStart, mEnd, target); +} + /*virtual*/ F32 LLOnHoverChangeableTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect) { @@ -3692,6 +3986,13 @@ LLInlineViewSegment::~LLInlineViewSegment() mView->die(); } +// virtual +LLTextSegmentPtr LLInlineViewSegment::clone(LLTextBase& target) const +{ + llassert_always_msg(false, "NOT SUPPORTED"); + return nullptr; +} + bool LLInlineViewSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { if (first_char == 0 && num_chars == 0) @@ -3703,8 +4004,7 @@ bool LLInlineViewSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& w if (mForceNewLine) { // Chat, string can't be smaller then font height even if it is empty - LLStyleSP s(new LLStyle(LLStyle::Params().visible(true))); - height = s->getFont()->getLineHeight(); + height = LLStyle::getDefaultFont()->getLineHeight(); return true; // new line } @@ -3768,9 +4068,7 @@ void LLInlineViewSegment::linkToDocument(LLTextBase* editor) LLLineBreakTextSegment::LLLineBreakTextSegment(S32 pos):LLTextSegment(pos,pos+1) { - LLStyleSP s( new LLStyle(LLStyle::Params().visible(true))); - - mFontHeight = s->getFont()->getLineHeight(); + mFontHeight = LLStyle::getDefaultFont()->getLineHeight(); } LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLTextSegment(pos,pos+1) { @@ -3779,6 +4077,14 @@ LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLT LLLineBreakTextSegment::~LLLineBreakTextSegment() { } + +// virtual +LLTextSegmentPtr LLLineBreakTextSegment::clone(LLTextBase& target) const +{ + LLLineBreakTextSegment* copy = new LLLineBreakTextSegment(mStart); + copy->mFontHeight = mFontHeight; + return copy; +} bool LLLineBreakTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; @@ -3806,8 +4112,16 @@ LLImageTextSegment::~LLImageTextSegment() { } +// virtual +LLTextSegmentPtr LLImageTextSegment::clone(LLTextBase& target) const +{ + LLStyleConstSP sp(cloneStyle(target, mStyle)); + return new LLImageTextSegment(sp, mStart, target); +} + static const S32 IMAGE_HPAD = 3; +// virtual bool LLImageTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 00cf66b134..8ca653acb9 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -30,10 +30,12 @@ #include "v4color.h" #include "lleditmenuhandler.h" +#include "llfontvertexbuffer.h" #include "llspellcheckmenuhandler.h" #include "llstyle.h" #include "llkeywords.h" #include "llpanel.h" +#include "llurlmatch.h" #include <string> #include <vector> @@ -44,6 +46,7 @@ class LLScrollContainer; class LLContextMenu; class LLUrlMatch; +class LLTextBase; /// /// A text segment is used to specify a subsection of a text string @@ -61,6 +64,9 @@ public: mEnd(end) {} virtual ~LLTextSegment(); + virtual LLTextSegmentPtr clone(LLTextBase& terget) const { return new LLTextSegment(mStart, mEnd); } + static LLStyleSP cloneStyle(LLTextBase& target, const LLStyle* source); + bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; virtual bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; @@ -127,18 +133,19 @@ public: LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); LLNormalTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true); virtual ~LLNormalTextSegment(); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& 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, S32 line_ind) const; + /*virtual*/ void updateLayout(const class LLTextBase& editor); /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); - /*virtual*/ bool canEdit() const { return true; } + /*virtual*/ bool canEdit() const { return mCanEdit; } /*virtual*/ const LLUIColor& getColor() const { return mStyle->getColor(); } /*virtual*/ LLStyleConstSP getStyle() const { return mStyle; } /*virtual*/ void setStyle(LLStyleConstSP style) { mStyle = style; } /*virtual*/ void setToken( LLKeywordToken* token ) { mToken = token; } /*virtual*/ LLKeywordToken* getToken() const { return mToken; } - /*virtual*/ bool getToolTip( std::string& msg ) const; /*virtual*/ void setToolTip(const std::string& tooltip); /*virtual*/ void dump() const; @@ -149,11 +156,14 @@ public: /*virtual*/ bool handleToolTip(S32 x, S32 y, MASK mask); protected: + virtual bool useFontBuffers() const { return true; } F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRectf rect); virtual const LLWString& getWText() const; virtual const S32 getLength() const; + void setAllowEdit(bool can_edit) { mCanEdit = can_edit; } + protected: class LLTextBase& mEditor; LLStyleConstSP mStyle; @@ -161,6 +171,14 @@ protected: LLKeywordToken* mToken; std::string mTooltip; boost::signals2::connection mImageLoadedConnection; + + bool mCanEdit { true }; + + // font rendering + LLFontVertexBuffer mFontBufferPreSelection; + LLFontVertexBuffer mFontBufferSelection; + LLFontVertexBuffer mFontBufferPostSelection; + S32 mLastGeneration = -1; }; // This text segment is the same as LLNormalTextSegment, the only difference @@ -171,6 +189,7 @@ class LLLabelTextSegment : public LLNormalTextSegment public: LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor ); LLLabelTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; protected: @@ -185,6 +204,7 @@ class LLEmojiTextSegment : public LLNormalTextSegment public: LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor); LLEmojiTextSegment(const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible = true); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const override; bool canEdit() const override { return false; } bool handleToolTip(S32 x, S32 y, MASK mask) override; @@ -195,6 +215,7 @@ class LLOnHoverChangeableTextSegment : public LLNormalTextSegment { public: LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor ); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); /*virtual*/ bool handleHover(S32 x, S32 y, MASK mask); protected: @@ -209,6 +230,7 @@ class LLIndexSegment : public LLTextSegment { public: LLIndexSegment() : LLTextSegment(0, 0) {} + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const { return new LLIndexSegment(); } }; class LLInlineViewSegment : public LLTextSegment @@ -226,6 +248,8 @@ public: LLInlineViewSegment(const Params& p, S32 start, S32 end); ~LLInlineViewSegment(); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; /*virtual*/ void updateLayout(const class LLTextBase& editor); @@ -250,6 +274,7 @@ public: LLLineBreakTextSegment(LLStyleConstSP style,S32 pos); LLLineBreakTextSegment(S32 pos); ~LLLineBreakTextSegment(); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const; F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); @@ -263,6 +288,8 @@ class LLImageTextSegment : public LLTextSegment public: LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor); ~LLImageTextSegment(); + /*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const; + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const; S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 char_offset, S32 max_chars, S32 line_ind) const; F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect); @@ -427,11 +454,12 @@ public: virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style /*virtual*/ const std::string& getText() const override; void setMaxTextLength(S32 length) { mMaxTextByteLength = length; } - S32 getMaxTextLength() { return mMaxTextByteLength; } + S32 getMaxTextLength() const { return mMaxTextByteLength; } // wide-char versions void setWText(const LLWString& text); const LLWString& getWText() const; + S32 getTextGeneration() const; void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params()); @@ -465,20 +493,20 @@ public: LLRect getTextBoundingRect(); LLRect getVisibleDocumentRect() const; - S32 getVPad() { return mVPad; } - S32 getHPad() { return mHPad; } - F32 getLineSpacingMult() { return mLineSpacingMult; } - S32 getLineSpacingPixels() { return mLineSpacingPixels; } // only for multiline + S32 getVPad() const { return mVPad; } + S32 getHPad() const { return mHPad; } + F32 getLineSpacingMult() const { return mLineSpacingMult; } + S32 getLineSpacingPixels() const { return mLineSpacingPixels; } // only for multiline S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, bool round, bool hit_past_end_of_line = true) const; LLRect getLocalRectFromDocIndex(S32 pos) const; LLRect getDocRectFromDocIndex(S32 pos) const; void setReadOnly(bool read_only) { mReadOnly = read_only; } - bool getReadOnly() { return mReadOnly; } + bool getReadOnly() const { return mReadOnly; } void setSkipLinkUnderline(bool skip_link_underline) { mSkipLinkUnderline = skip_link_underline; } - bool getSkipLinkUnderline() { return mSkipLinkUnderline; } + bool getSkipLinkUnderline() const { return mSkipLinkUnderline; } void setParseURLs(bool parse_urls) { mParseHTML = parse_urls; } @@ -492,14 +520,15 @@ public: void endOfLine(); void startOfDoc(); void endOfDoc(); - void changePage( S32 delta ); - void changeLine( S32 delta ); + void changePage(S32 delta); + void changeLine(S32 delta); bool scrolledToStart(); bool scrolledToEnd(); const LLFontGL* getFont() const override { return mFont; } + virtual void copyContents(const LLTextBase* source); virtual void appendLineBreakSegment(const LLStyle::Params& style_params); virtual void appendImageSegment(const LLStyle::Params& style_params); virtual void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo); @@ -582,6 +611,7 @@ protected: bool operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const; }; typedef std::multiset<LLTextSegmentPtr, compare_segment_end> segment_set_t; + typedef LLStyle::EUnderlineLink e_underline; // member functions LLTextBase(const Params &p); @@ -595,12 +625,13 @@ protected: virtual void drawSelectionBackground(); // draws the black box behind the selected text void drawCursor(); void drawText(); + void drawHighlightedBackground(); // modify contents 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, bool underline_on_hover_only = false); + void appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& stylep, e_underline underline_link = e_underline::UNDERLINE_ALWAYS); // manage segments @@ -648,8 +679,8 @@ protected: // avatar names are looked up. void replaceUrl(const std::string &url, const std::string &label, const std::string& icon); - 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, bool underline_on_hover_only = false); + void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params(), bool force_slurl = false); + void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, e_underline underline_link = e_underline::UNDERLINE_ALWAYS); S32 normalizeUri(std::string& uri); protected: @@ -660,6 +691,7 @@ protected: } std::vector<LLRect> getSelectionRects(); + std::vector<std::pair<LLRect, LLUIColor>> getHighlightedBgRects(); protected: // text segmentation and flow diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 05af36b71e..9f945d3735 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -159,7 +159,8 @@ LLSD LLTextBox::getValue() const bool LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text ) { mText.setArg(key, text); - LLTextBase::setText(mText.getString()); + static const LLStyle::Params input_params = LLStyle::Params(); + LLTextBase::setText(mText.getString(), input_params); return true; } diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index a3cde45cd0..507d8f3ee6 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -46,36 +46,42 @@ protected: friend class LLUICtrlFactory; public: - virtual ~LLTextBox(); + ~LLTextBox() override; - /*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleHover(S32 x, S32 y, MASK mask); + bool handleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleMouseUp(S32 x, S32 y, MASK mask) override; + bool handleHover(S32 x, S32 y, MASK mask) override; - /*virtual*/ void setEnabled(bool enabled); + void setEnabled(bool enabled) override; - /*virtual*/ void setText( const LLStringExplicit& text, const LLStyle::Params& input_params = LLStyle::Params() ); + void setText(const LLStringExplicit& text, const LLStyle::Params& input_params = LLStyle::Params()) override; - void setRightAlign() { mHAlign = LLFontGL::RIGHT; } - void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } - void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ); + void setRightAlign() { mHAlign = LLFontGL::RIGHT; } + void setHAlign(LLFontGL::HAlign align) { mHAlign = align; } + void setClickedCallback(boost::function<void(void*)> cb, void* userdata = NULL); - void reshapeToFitText(bool called_from_parent = false); + void reshapeToFitText(bool called_from_parent = false); - S32 getTextPixelWidth(); - S32 getTextPixelHeight(); + S32 getTextPixelWidth(); + S32 getTextPixelHeight(); - /*virtual*/ LLSD getValue() const; - /*virtual*/ bool setTextArg( const std::string& key, const LLStringExplicit& text ); + LLSD getValue() const override; + bool setTextArg(const std::string& key, const LLStringExplicit& text) override; - void setShowCursorHand(bool show_cursor) { mShowCursorHand = show_cursor; } + void setShowCursorHand(bool show_cursor) { mShowCursorHand = show_cursor; } protected: - void onUrlLabelUpdated(const std::string &url, const std::string &label); + void onUrlLabelUpdated(const std::string& url, const std::string& label); LLUIString mText; callback_t mClickedCallback; bool mShowCursorHand; + +protected: + virtual std::string _getSearchText() const override + { + return LLTextBase::_getSearchText() + mText.getString(); + } }; // Build time optimization, generate once in .cpp file diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index cbbb164cb2..cfe729be06 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -60,6 +60,7 @@ #include "llurlregistry.h" #include "lltooltip.h" #include "llmenugl.h" +#include "llchatmentionhelper.h" #include <queue> #include "llcombobox.h" @@ -167,50 +168,6 @@ private: }; /////////////////////////////////////////////////////////////////// -class LLTextEditor::TextCmdAddString : public LLTextBase::TextCmd -{ -public: - TextCmdAddString(S32 pos, bool group_with_next, char *str, - LLTextSegmentPtr segment) : - TextCmd(pos, group_with_next, segment), - mWString(utf8str_to_wstring(str)), - mBlockExtensions(FALSE) - { - } - virtual void blockExtensions() - { - mBlockExtensions = TRUE; - } - virtual bool canExtend(S32 pos) const - { - if (!mSegments.empty()) return FALSE; - - return !mBlockExtensions - && (pos == getPosition() + (S32)mWString.length()); - } - virtual bool execute(LLTextBase* editor, S32* delta) - { - *delta = insert(editor, getPosition(), mWString); - LLWStringUtil::truncate(mWString, *delta); - return (*delta != 0); - } - virtual S32 undo(LLTextBase* editor) - { - remove(editor, getPosition(), mWString.length()); - return getPosition(); - } - virtual S32 redo(LLTextBase* editor) - { - insert(editor, getPosition(), mWString); - return getPosition() + mWString.length(); - } - -private: - LLWString mWString; - bool mBlockExtensions; -}; - -/////////////////////////////////////////////////////////////////// class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd { @@ -253,8 +210,15 @@ public: } virtual bool execute( LLTextBase* editor, S32* delta ) { - mWString = editor->getWText().substr(getPosition(), mLen); - *delta = remove(editor, getPosition(), mLen ); + try + { + mWString = editor->getWText().substr(getPosition(), mLen); + *delta = remove(editor, getPosition(), mLen); + } + catch (std::out_of_range&) + { + return false; + } return (*delta != 0); } virtual S32 undo( LLTextBase* editor ) @@ -307,6 +271,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mPrevalidator(p.prevalidator()), mShowContextMenu(p.show_context_menu), mShowEmojiHelper(p.show_emoji_helper), + mShowChatMentionPicker(false), mEnableTooltipPaste(p.enable_tooltip_paste), mPassDelete(false), mKeepSelectionOnReturn(false) @@ -751,6 +716,30 @@ void LLTextEditor::handleEmojiCommit(llwchar emoji) } } +void LLTextEditor::handleMentionCommit(std::string name_url) +{ + S32 mention_start_pos; + if (LLChatMentionHelper::instance().isCursorInNameMention(getWText(), mCursorPos, &mention_start_pos)) + { + remove(mention_start_pos, mCursorPos - mention_start_pos, true); + insert(mention_start_pos, utf8str_to_wstring(name_url), false, LLTextSegmentPtr()); + + std::string new_text(wstring_to_utf8str(getConvertedText())); + clear(); + appendTextImpl(new_text, LLStyle::Params(), true); + + segment_set_t::const_iterator it = getSegIterContaining(mention_start_pos); + if (it != mSegments.end()) + { + setCursorPos((*it)->getEnd() + 1); + } + else + { + setCursorPos(mention_start_pos); + } + } +} + bool LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { bool handled = false; @@ -1140,6 +1129,7 @@ void LLTextEditor::removeCharOrTab() } tryToShowEmojiHelper(); + tryToShowMentionHelper(); } else { @@ -1165,6 +1155,7 @@ void LLTextEditor::removeChar() setCursorPos(mCursorPos - 1); removeChar(mCursorPos); tryToShowEmojiHelper(); + tryToShowMentionHelper(); } else { @@ -1208,18 +1199,6 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc) return execute(new TextCmdAddChar(pos, false, wc, LLTextSegmentPtr())); } -S32 LLTextEditor::addString(S32 pos, char *str) -{ - if ((wstring_utf8_length(getWText()) + strlen(str)) - > mMaxTextByteLength) { - make_ui_sound("UISndBadKeystroke"); - return 0; - } - - return execute(new TextCmdAddString(pos, FALSE, str, - LLTextSegmentPtr())); -} - void LLTextEditor::addChar(llwchar wc) { if (!getEnabled()) @@ -1238,6 +1217,7 @@ void LLTextEditor::addChar(llwchar wc) setCursorPos(mCursorPos + addChar( mCursorPos, wc )); tryToShowEmojiHelper(); + tryToShowMentionHelper(); if (!mReadOnly && mAutoreplaceCallback != NULL) { @@ -1257,38 +1237,6 @@ void LLTextEditor::addChar(llwchar wc) } } -void LLTextEditor::addString(char *str, bool editing) -{ - if (!getEnabled()) - return; - if (hasSelection()) - deleteSelection(TRUE); - else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) - removeChar(mCursorPos); - else if (editing) { - clear(); - setCursorPos(0); - } - - setCursorPos(mCursorPos + addString(mCursorPos, str)); - - if (!mReadOnly && mAutoreplaceCallback != NULL) { - S32 replacement_start; - S32 replacement_length; - LLWString replacement_string; - S32 new_cursor_pos = mCursorPos; - mAutoreplaceCallback(replacement_start, replacement_length, - replacement_string, new_cursor_pos, getWText()); - - if (replacement_length > 0 || !replacement_string.empty()) { - remove(replacement_start, replacement_length, true); - insert(replacement_start, replacement_string, false, - LLTextSegmentPtr()); - setCursorPos(new_cursor_pos); - } - } -} - void LLTextEditor::showEmojiHelper() { if (mReadOnly || !mShowEmojiHelper) @@ -1299,6 +1247,14 @@ void LLTextEditor::showEmojiHelper() LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, LLStringUtil::null, cb); } +void LLTextEditor::hideEmojiHelper() +{ + if (mShowEmojiHelper) + { + LLEmojiHelper::instance().hideHelper(this); + } +} + void LLTextEditor::tryToShowEmojiHelper() { if (mReadOnly || !mShowEmojiHelper) @@ -1320,6 +1276,31 @@ void LLTextEditor::tryToShowEmojiHelper() } } +void LLTextEditor::tryToShowMentionHelper() +{ + if (mReadOnly || !mShowChatMentionPicker) + return; + + S32 mention_start_pos; + LLWString text(getWText()); + if (LLChatMentionHelper::instance().isCursorInNameMention(text, mCursorPos, &mention_start_pos)) + { + const LLRect cursor_rect(getLocalRectFromDocIndex(mention_start_pos)); + std::string name_part(wstring_to_utf8str(text.substr(mention_start_pos, mCursorPos - mention_start_pos))); + name_part.erase(0, 1); + auto cb = [this](std::string name_url) + { + handleMentionCommit(name_url); + }; + LLChatMentionHelper::instance().showHelper(this, cursor_rect.mLeft, cursor_rect.mTop, name_part, cb); + } + else + { + LLChatMentionHelper::instance().hideHelper(); + } +} + + void LLTextEditor::addLineBreakChar(bool group_together) { if( !getEnabled() ) @@ -1946,7 +1927,7 @@ bool LLTextEditor::handleKeyHere(KEY key, MASK mask ) // not handled and let the parent take care of field movement. if (KEY_TAB == key && mTabsToNextField) { - return false; + return mShowChatMentionPicker && LLChatMentionHelper::instance().handleKey(this, key, mask); } if (mReadOnly && mScroller) @@ -1957,9 +1938,13 @@ bool LLTextEditor::handleKeyHere(KEY key, MASK mask ) } else { - if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) + if (!mReadOnly) { - return true; + if ((mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) || + (mShowChatMentionPicker && LLChatMentionHelper::instance().handleKey(this, key, mask))) + { + return true; + } } if (mEnableTooltipPaste && @@ -2060,24 +2045,6 @@ bool LLTextEditor::handleUnicodeCharHere(llwchar uni_char) return handled; } -bool LLTextEditor::handleUnicodeStringHere(char *uni_str, bool editing) -{ - auto handled = FALSE; - - if (!mReadOnly) { - addString(uni_str, editing); - getWindow()->hideCursorUntilMouseMove(); - handled = TRUE; - } - - if (handled) { - resetCursorBlink(); - deselect(); - onKeyStroke(); - } - - return handled; -} // virtual bool LLTextEditor::canDoDelete() const @@ -3174,3 +3141,21 @@ S32 LLTextEditor::spacesPerTab() { return SPACES_PER_TAB; } + +LLWString LLTextEditor::getConvertedText() const +{ + LLWString text = getWText(); + S32 diff = 0; + for (auto segment : mSegments) + { + if (segment && segment->getStyle() && segment->getStyle()->getDrawHighlightBg()) + { + S32 seg_length = segment->getEnd() - segment->getStart(); + std::string slurl = segment->getStyle()->getLinkHREF(); + + text.replace(segment->getStart() + diff, seg_length, utf8str_to_wstring(slurl)); + diff += (S32)slurl.size() - seg_length; + } + } + return text; +} diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 47dcadf090..882bb145df 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -95,6 +95,8 @@ public: void insertEmoji(llwchar emoji); void handleEmojiCommit(llwchar emoji); + void handleMentionCommit(std::string name_url); + // mousehandler overrides virtual bool handleMouseDown(S32 x, S32 y, MASK mask); virtual bool handleMouseUp(S32 x, S32 y, MASK mask); @@ -105,7 +107,6 @@ public: virtual bool handleKeyHere(KEY key, MASK mask ); virtual bool handleUnicodeCharHere(llwchar uni_char); - virtual bool handleUnicodeStringHere(char *uni_str, bool editing); virtual void onMouseCaptureLost(); @@ -201,24 +202,24 @@ public: const LLUUID& getSourceID() const { return mSourceID; } const LLTextSegmentPtr getPreviousSegment() const; - const LLTextSegmentPtr getLastSegment() const; void getSelectedSegments(segment_vec_t& segments) const; void setShowContextMenu(bool show) { mShowContextMenu = show; } bool getShowContextMenu() const { return mShowContextMenu; } void showEmojiHelper(); + void hideEmojiHelper(); void setShowEmojiHelper(bool show); bool getShowEmojiHelper() const { return mShowEmojiHelper; } void setPassDelete(bool b) { mPassDelete = b; } + LLWString getConvertedText() const; + protected: void showContextMenu(S32 x, S32 y); void drawPreeditMarker(); - void assignEmbedded(const std::string &s); - void removeCharOrTab(); void indentSelectedLines( S32 spaces ); @@ -238,7 +239,6 @@ protected: void autoIndent(); - void findEmbeddedItemSegments(S32 start, S32 end); void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const; virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } @@ -250,8 +250,6 @@ protected: // Undoable operations void addChar(llwchar c); // at mCursorPos S32 addChar(S32 pos, llwchar wc); - void addString(char *s, bool editing); - S32 addString(S32 pos, char *str); void addLineBreakChar(bool group_together = false); S32 overwriteChar(S32 pos, llwchar wc); void removeChar(); @@ -260,6 +258,7 @@ protected: S32 remove(S32 pos, S32 length, bool group_with_next_op); void tryToShowEmojiHelper(); + void tryToShowMentionHelper(); void focusLostHelper(); void updateAllowingLanguageInput(); bool hasPreeditString() const; @@ -274,6 +273,8 @@ protected: virtual bool getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; virtual S32 getPreeditFontSize() const; virtual LLWString getPreeditString() const { return getWText(); } + + virtual bool useFontBuffers() const { return getReadOnly(); } // // Protected data // @@ -295,6 +296,7 @@ protected: bool mAutoIndent; bool mParseOnTheFly; + bool mShowChatMentionPicker; void updateLinkSegments(); void keepSelectionOnReturn(bool keep) { mKeepSelectionOnReturn = keep; } @@ -305,7 +307,7 @@ private: // Methods // void pasteHelper(bool is_primary); - void cleanStringForPaste(LLWString & clean_string); + void cleanStringForPaste(LLWString& clean_string); void pasteTextWithLinebreaks(LLWString & clean_string); void onKeyStroke(); @@ -313,7 +315,6 @@ private: // Concrete TextCmd sub-classes used by the LLTextEditor base class class TextCmdInsert; class TextCmdAddChar; - class TextCmdAddString; class TextCmdOverwriteChar; class TextCmdRemove; diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h index c57c979525..5556406fbd 100644 --- a/indra/llui/lltoolbar.h +++ b/indra/llui/lltoolbar.h @@ -68,7 +68,7 @@ public: void reshape(S32 width, S32 height, bool called_from_parent = true); void setEnabled(bool enabled); void setCommandId(const LLCommandId& id) { mId = id; } - LLCommandId getCommandId() { return mId; } + LLCommandId getCommandId() const { return mId; } void setStartDragCallback(tool_startdrag_callback_t cb) { mStartDragItemCallback = cb; } void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; } @@ -256,7 +256,7 @@ public: // Methods used in loading and saving toolbar settings void setButtonType(LLToolBarEnums::ButtonType button_type); - LLToolBarEnums::ButtonType getButtonType() { return mButtonType; } + LLToolBarEnums::ButtonType getButtonType() const { return mButtonType; } command_id_list_t& getCommandsList() { return mButtonCommands; } void clearCommandsList(); diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 86525c2f7e..74f03618cf 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -390,22 +390,22 @@ void LLToolTip::draw() } } -bool LLToolTip::isFading() +bool LLToolTip::isFading() const { return mFadeTimer.getStarted(); } -F32 LLToolTip::getVisibleTime() +F32 LLToolTip::getVisibleTime() const { return mVisibleTimer.getStarted() ? mVisibleTimer.getElapsedTimeF32() : 0.f; } -bool LLToolTip::hasClickCallback() +bool LLToolTip::hasClickCallback() const { return mHasClickCallback; } -void LLToolTip::getToolTipMessage(std::string & message) +void LLToolTip::getToolTipMessage(std::string& message) const { if (mTextBox) { diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h index 8515504e3b..760acddd6f 100644 --- a/indra/llui/lltooltip.h +++ b/indra/llui/lltooltip.h @@ -44,15 +44,15 @@ public: Params(); }; LLToolTipView(const LLToolTipView::Params&); - /*virtual*/ bool handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleMiddleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ bool handleScrollWheel( S32 x, S32 y, S32 clicks ); + bool handleHover(S32 x, S32 y, MASK mask) override; + bool handleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleMiddleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleRightMouseDown(S32 x, S32 y, MASK mask) override; + bool handleScrollWheel( S32 x, S32 y, S32 clicks ) override; void drawStickyRect(); - /*virtual*/ void draw(); + void draw() override; }; class LLToolTip : public LLPanel @@ -98,20 +98,20 @@ public: Params(); }; - /*virtual*/ void draw(); - /*virtual*/ bool handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); - /*virtual*/ void setVisible(bool visible); + void draw() override; + bool handleHover(S32 x, S32 y, MASK mask) override; + void onMouseLeave(S32 x, S32 y, MASK mask) override; + void setVisible(bool visible) override; - bool isFading(); - F32 getVisibleTime(); - bool hasClickCallback(); + bool isFading() const; + F32 getVisibleTime() const; + bool hasClickCallback() const; LLToolTip(const Params& p); virtual void initFromParams(const LLToolTip::Params& params); - void getToolTipMessage(std::string & message); - bool isTooltipPastable() { return mIsTooltipPastable; } + void getToolTipMessage(std::string & message) const; + bool isTooltipPastable() const { return mIsTooltipPastable; } protected: void updateTextBox(); diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp index 8410031653..0c6c5b64e4 100644 --- a/indra/llui/lltrans.cpp +++ b/indra/llui/lltrans.cpp @@ -28,12 +28,8 @@ #include "lltrans.h" -#include "llfasttimer.h" // for call count statistics #include "llxuiparser.h" #include "llsd.h" -#include "llxmlnode.h" - -#include <map> LLTrans::template_map_t LLTrans::sStringTemplates; LLTrans::template_map_t LLTrans::sDefaultStringTemplates; @@ -59,7 +55,7 @@ struct StringTable : public LLInitParam::Block<StringTable> }; //static -bool LLTrans::parseStrings(LLXMLNodePtr &root, const std::set<std::string>& default_args) +bool LLTrans::parseStrings(LLXMLNodePtr& root, const std::set<std::string>& default_args) { std::string xml_filename = "(strings file)"; if (!root->hasName("strings")) @@ -107,7 +103,7 @@ bool LLTrans::parseStrings(LLXMLNodePtr &root, const std::set<std::string>& defa //static -bool LLTrans::parseLanguageStrings(LLXMLNodePtr &root) +bool LLTrans::parseLanguageStrings(LLXMLNodePtr& root) { std::string xml_filename = "(language strings file)"; if (!root->hasName("strings")) @@ -138,10 +134,6 @@ bool LLTrans::parseLanguageStrings(LLXMLNodePtr &root) return true; } - - -static LLTrace::BlockTimerStatHandle FTM_GET_TRANS("Translate string"); - //static std::string LLTrans::getString(std::string_view xml_desc, const LLStringUtil::format_map_t& msg_args, bool def_string) { @@ -235,7 +227,7 @@ std::string LLTrans::getDefString(std::string_view xml_desc, const LLSD& msg_arg } //static -bool LLTrans::findString(std::string &result, std::string_view xml_desc, const LLStringUtil::format_map_t& msg_args) +bool LLTrans::findString(std::string& result, std::string_view xml_desc, const LLStringUtil::format_map_t& msg_args) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; @@ -257,7 +249,7 @@ bool LLTrans::findString(std::string &result, std::string_view xml_desc, const L } //static -bool LLTrans::findString(std::string &result, std::string_view xml_desc, const LLSD& msg_args) +bool LLTrans::findString(std::string& result, std::string_view xml_desc, const LLSD& msg_args) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; @@ -277,7 +269,7 @@ bool LLTrans::findString(std::string &result, std::string_view xml_desc, const L } //static -std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count) +std::string LLTrans::getCountString(std::string_view language, std::string_view xml_desc, S32 count) { // Compute which string identifier to use const char* form = ""; @@ -337,7 +329,7 @@ std::string LLTrans::getCountString(const std::string& language, const std::stri args["[COUNT]"] = llformat("%d", count); // Look up "AgeYearsB" or "AgeWeeksC" including the "form" - std::string key = llformat("%s%s", xml_desc.c_str(), form); + std::string key = llformat("%s%s", xml_desc.data(), form); return getString(key, args); } diff --git a/indra/llui/lltrans.h b/indra/llui/lltrans.h index 3492ed0169..c5d01e6f8d 100644 --- a/indra/llui/lltrans.h +++ b/indra/llui/lltrans.h @@ -30,10 +30,8 @@ #include <map> #include <set> -#include "llpointer.h" #include "llstring.h" - -class LLXMLNode; +#include "llxmlnode.h" class LLSD; @@ -58,17 +56,17 @@ public: class LLTrans { public: - LLTrans(); + LLTrans() = default; /** * @brief Parses the xml root that holds the strings. Used once on startup -// *FIXME * @param xml_filename Filename to parse + * @param root xml root node to parse * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" * @returns true if the file was parsed successfully, true if something went wrong */ - static bool parseStrings(LLPointer<LLXMLNode> & root, const std::set<std::string>& default_args); + static bool parseStrings(LLXMLNodePtr& root, const std::set<std::string>& default_args); - static bool parseLanguageStrings(LLPointer<LLXMLNode> & root); + static bool parseLanguageStrings(LLXMLNodePtr& root); /** * @brief Returns a translated string @@ -80,14 +78,14 @@ public: static std::string getDefString(std::string_view xml_desc, const LLStringUtil::format_map_t& args); static std::string getString(std::string_view xml_desc, const LLSD& args, bool def_string = false); static std::string getDefString(std::string_view xml_desc, const LLSD& args); - static bool findString(std::string &result, std::string_view xml_desc, const LLStringUtil::format_map_t& args); - static bool findString(std::string &result, std::string_view xml_desc, const LLSD& args); + static bool findString(std::string& result, std::string_view xml_desc, const LLStringUtil::format_map_t& args); + static bool findString(std::string& result, std::string_view xml_desc, const LLSD& args); // Returns translated string with [COUNT] replaced with a number, following // special per-language logic for plural nouns. For example, some languages // may have different plurals for 0, 1, 2 and > 2. // See "AgeWeeksA", "AgeWeeksB", etc. in strings.xml for examples. - static std::string getCountString(const std::string& language, const std::string& xml_desc, S32 count); + static std::string getCountString(std::string_view language, std::string_view xml_desc, S32 count); /** * @brief Returns a translated string diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp index 4af5376a8b..e82af0b96f 100644 --- a/indra/llui/lltransutil.cpp +++ b/indra/llui/lltransutil.cpp @@ -48,7 +48,7 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<s "Second Life viewer couldn't access some of the files it needs and will be closed." "\n\nPlease reinstall viewer from https://secondlife.com/support/downloads/ and " "contact https://support.secondlife.com if issue persists after reinstall."; - LLError::LLUserWarningMsg::show(error_string); + LLError::LLUserWarningMsg::show(error_string, LLError::LLUserWarningMsg::ERROR_MISSING_FILES); gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << LL_ENDL; return false; diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 375cd539b7..b2dcb6dc88 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -31,8 +31,6 @@ #include "llrect.h" #include "llcoord.h" #include "llcontrol.h" -#include "llcoord.h" -#include "llcontrol.h" #include "llinitparam.h" #include "llregistry.h" #include "llrender2dutils.h" @@ -156,7 +154,7 @@ public: sanitizeRange(); } - S32 clamp(S32 input) + S32 clamp(S32 input) const { if (input < mMin) return mMin; if (input > mMax) return mMax; @@ -170,8 +168,8 @@ public: sanitizeRange(); } - S32 getMin() { return mMin; } - S32 getMax() { return mMax; } + S32 getMin() const { return mMin; } + S32 getMax() const { return mMax; } bool operator==(const RangeS32& other) const { @@ -225,7 +223,7 @@ public: mValue = clamp(value); } - S32 get() + S32 get() const { return mValue; } @@ -255,7 +253,7 @@ public: static std::string getLanguage(); // static for lldateutil_test compatibility //helper functions (should probably move free standing rendering helper functions here) - LLView* getRootView() { return mRootView; } + LLView* getRootView() const { return mRootView; } void setRootView(LLView* view) { mRootView = view; } /** * Walk the LLView tree to resolve a path @@ -298,7 +296,7 @@ public: LLControlGroup& getControlControlGroup (std::string_view controlname); F32 getMouseIdleTime() { return mMouseIdleTimer.getElapsedTimeF32(); } void resetMouseIdleTimer() { mMouseIdleTimer.reset(); } - LLWindow* getWindow() { return mWindow; } + LLWindow* getWindow() const { return mWindow; } void addPopup(LLView*); void removePopup(LLView*); diff --git a/indra/llui/lluiconstants.h b/indra/llui/lluiconstants.h index 5fdfd37c6e..a317c66008 100644 --- a/indra/llui/lluiconstants.h +++ b/indra/llui/lluiconstants.h @@ -28,23 +28,23 @@ #define LL_LLUICONSTANTS_H // spacing for small font lines of text, like LLTextBoxes -const S32 LINE = 16; +constexpr S32 LINE = 16; // spacing for larger lines of text -const S32 LINE_BIG = 24; +constexpr S32 LINE_BIG = 24; // default vertical padding -const S32 VPAD = 4; +constexpr S32 VPAD = 4; // default horizontal padding -const S32 HPAD = 4; +constexpr S32 HPAD = 4; // Account History, how far to look into past -const S32 SUMMARY_INTERVAL = 7; // one week -const S32 SUMMARY_MAX = 8; // -const S32 DETAILS_INTERVAL = 1; // one day -const S32 DETAILS_MAX = 30; // one month -const S32 TRANSACTIONS_INTERVAL = 1;// one day -const S32 TRANSACTIONS_MAX = 30; // one month +constexpr S32 SUMMARY_INTERVAL = 7; // one week +constexpr S32 SUMMARY_MAX = 8; // +constexpr S32 DETAILS_INTERVAL = 1; // one day +constexpr S32 DETAILS_MAX = 30; // one month +constexpr S32 TRANSACTIONS_INTERVAL = 1;// one day +constexpr S32 TRANSACTIONS_MAX = 30; // one month #endif diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 8cd9950917..bcaf479b0f 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -39,9 +39,9 @@ #include "llviewmodel.h" // *TODO move dependency to .cpp file #include "llsearchablecontrol.h" -const bool TAKE_FOCUS_YES = true; -const bool TAKE_FOCUS_NO = false; -const S32 DROP_SHADOW_FLOATER = 5; +constexpr bool TAKE_FOCUS_YES = true; +constexpr bool TAKE_FOCUS_NO = false; +constexpr S32 DROP_SHADOW_FLOATER = 5; class LLUICtrl : public LLView, public boost::signals2::trackable diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 75e7e396bc..91221dc7f3 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -184,7 +184,7 @@ fail: template<class T> static T* getDefaultWidget(std::string_view name) { - typename T::Params widget_params; + typename T::Params widget_params{}; widget_params.name = std::string(name); return create<T>(widget_params); } diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index bfadeb8428..ab6de16639 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -47,6 +47,12 @@ void LLUIString::assign(const std::string& s) dirty(); } +void LLUIString::assign(const LLWString& instring) +{ + mOrig = wstring_to_utf8str(instring); + dirty(); +} + void LLUIString::setArgList(const LLStringUtil::format_map_t& args) { diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index b9d4ff0ebb..950d4e72c6 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -61,10 +61,11 @@ public: LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {} LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args); LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); } - LLUIString(const LLWString& instring) : mArgs(NULL) { insert(0, instring); } + LLUIString(const LLWString& instring) : mArgs(NULL) { assign(instring); } ~LLUIString() { delete mArgs; } void assign(const std::string& instring); + void assign(const LLWString& instring); LLUIString& operator=(const std::string& s) { assign(s); return *this; } void setArgList(const LLStringUtil::format_map_t& args); @@ -109,8 +110,8 @@ private: LLStringUtil::format_map_t* mArgs; // controls lazy evaluation - mutable bool mNeedsResult; - mutable bool mNeedsWResult; + mutable bool mNeedsResult { true }; + mutable bool mNeedsWResult { true }; }; #endif // LL_LLUISTRING_H diff --git a/indra/llui/llundo.h b/indra/llui/llundo.h index dc40702be0..990745e530 100644 --- a/indra/llui/llundo.h +++ b/indra/llui/llundo.h @@ -42,7 +42,7 @@ public: LLUndoAction(): mClusterID(0) {}; virtual ~LLUndoAction(){}; private: - S32 mClusterID; + S32 mClusterID; }; LLUndoBuffer( LLUndoAction (*create_func()), S32 initial_count ); @@ -51,8 +51,8 @@ public: LLUndoAction *getNextAction(bool setClusterBegin = true); bool undoAction(); bool redoAction(); - bool canUndo() { return (mNextAction != mFirstAction); } - bool canRedo() { return (mNextAction != mLastAction); } + bool canUndo() const { return (mNextAction != mFirstAction); } + bool canRedo() const { return (mNextAction != mLastAction); } void flushActions(); diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index 0f54b66299..ac9741a7ad 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -45,8 +45,6 @@ class LLUrlAction { public: - LLUrlAction(); - /// load a Url in the user's preferred web browser static void openURL(std::string url); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 79d2fcd049..bcd13b7f0b 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -29,7 +29,6 @@ #include "llurlentry.h" #include "lluictrl.h" #include "lluri.h" -#include "llurlmatch.h" #include "llurlregistry.h" #include "lluriparser.h" @@ -48,7 +47,7 @@ // Utility functions std::string localize_slapp_label(const std::string& url, const std::string& full_name); - +LLUUID LLUrlEntryBase::sAgentID(LLUUID::null); LLUrlEntryBase::LLUrlEntryBase() { } @@ -68,7 +67,7 @@ std::string LLUrlEntryBase::getIcon(const std::string &url) return mIcon; } -LLStyle::Params LLUrlEntryBase::getStyle() const +LLStyle::Params LLUrlEntryBase::getStyle(const std::string &url) const { LLStyle::Params style_params; style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); @@ -221,6 +220,16 @@ bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const }, L'\u002F'); // Solidus + std::replace_if(wlabel.begin(), + wlabel.end(), + [](const llwchar& chr) + { + return // Not a decomposition, but suficiently similar + (chr == L'\u04BA') // "Cyrillic Capital Letter Shha" + || (chr == L'\u04BB'); // "Cyrillic Small Letter Shha" + }, + L'\u0068'); // "Latin Small Letter H" + std::string label = wstring_to_utf8str(wlabel); if ((label.find(".com") != std::string::npos || label.find("www.") != std::string::npos) @@ -600,15 +609,15 @@ void LLUrlEntryAgent::callObservers(const std::string &id, void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name) { - avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id); - if (it != mAvatarNameCacheConnections.end()) + auto range = mAvatarNameCacheConnections.equal_range(id); + for (avatar_name_cache_connection_map_t::iterator it = range.first; it != range.second; ++it) { if (it->second.connected()) { it->second.disconnect(); } - mAvatarNameCacheConnections.erase(it); } + mAvatarNameCacheConnections.erase(range.first, range.second); std::string label = av_name.getCompleteName(); @@ -621,6 +630,11 @@ LLUUID LLUrlEntryAgent::getID(const std::string &string) const return LLUUID(getIDStringFromUrl(string)); } +bool LLUrlEntryAgent::isAgentID(const std::string& url) const +{ + return sAgentID == getID(url); +} + std::string LLUrlEntryAgent::getTooltip(const std::string &string) const { // return a tooltip corresponding to the URL type instead of the generic one @@ -657,10 +671,14 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const return LLTrans::getString("TooltipAgentUrl"); } -bool LLUrlEntryAgent::underlineOnHoverOnly(const std::string &string) const +LLStyle::EUnderlineLink LLUrlEntryAgent::getUnderline(const std::string& string) const { std::string url = getUrl(string); - return LLStringUtil::endsWith(url, "/about") || LLStringUtil::endsWith(url, "/inspect"); + if (LLStringUtil::endsWith(url, "/about") || LLStringUtil::endsWith(url, "/inspect")) + { + return LLStyle::EUnderlineLink::UNDERLINE_ON_HOVER; + } + return LLStyle::EUnderlineLink::UNDERLINE_ALWAYS; } std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb) @@ -695,27 +713,19 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa } else { - avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); - if (it != mAvatarNameCacheConnections.end()) - { - if (it->second.connected()) - { - it->second.disconnect(); - } - mAvatarNameCacheConnections.erase(it); - } - mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnections.emplace(agent_id, LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2))); addObserver(agent_id_string, url, cb); return LLTrans::getString("LoadingData"); } } -LLStyle::Params LLUrlEntryAgent::getStyle() const +LLStyle::Params LLUrlEntryAgent::getStyle(const std::string &url) const { - LLStyle::Params style_params = LLUrlEntryBase::getStyle(); + LLStyle::Params style_params = LLUrlEntryBase::getStyle(url); style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + return style_params; } @@ -750,6 +760,10 @@ std::string localize_slapp_label(const std::string& url, const std::string& full { return LLTrans::getString("SLappAgentRemoveFriend") + " " + full_name; } + if (LLStringUtil::endsWith(url, "/mention")) + { + return "@" + full_name; + } return full_name; } @@ -761,6 +775,36 @@ std::string LLUrlEntryAgent::getIcon(const std::string &url) return mIcon; } +/// +/// LLUrlEntryAgentMention Describes a chat mention Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/mention +/// +LLUrlEntryAgentMention::LLUrlEntryAgentMention() +{ + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/mention", boost::regex::perl | boost::regex::icase); + mMenuName = "menu_url_agent.xml"; + mIcon = std::string(); +} + +LLStyle::EUnderlineLink LLUrlEntryAgentMention::getUnderline(const std::string& string) const +{ + return LLStyle::EUnderlineLink::UNDERLINE_NEVER; +} + +LLStyle::Params LLUrlEntryAgentMention::getStyle(const std::string& url) const +{ + LLStyle::Params style_params = LLUrlEntryAgent::getStyle(url); + style_params.color = LLUIColorTable::instance().getColor("ChatMentionFont"); + style_params.readonly_color = LLUIColorTable::instance().getColor("ChatMentionFont"); + style_params.font.style = "NORMAL"; + style_params.draw_highlight_bg = true; + + LLUUID agent_id(getIDStringFromUrl(url)); + style_params.highlight_bg_color = LLUIColorTable::instance().getColor((agent_id == sAgentID) ? "ChatSelfMentionHighlight" : "ChatMentionHighlight"); + + return style_params; +} + // // LLUrlEntryAgentName describes a Second Life agent name Url, e.g., // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username) @@ -770,17 +814,17 @@ LLUrlEntryAgentName::LLUrlEntryAgentName() {} void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id, - const LLAvatarName& av_name) + const LLAvatarName& av_name) { - avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id); - if (it != mAvatarNameCacheConnections.end()) + auto range = mAvatarNameCacheConnections.equal_range(id); + for (avatar_name_cache_connection_map_t::iterator it = range.first; it != range.second; ++it) { if (it->second.connected()) { it->second.disconnect(); } - mAvatarNameCacheConnections.erase(it); } + mAvatarNameCacheConnections.erase(range.first, range.second); std::string label = getName(av_name); // received the agent name from the server - tell our observers @@ -815,23 +859,14 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab } else { - avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); - if (it != mAvatarNameCacheConnections.end()) - { - if (it->second.connected()) - { - it->second.disconnect(); - } - mAvatarNameCacheConnections.erase(it); - } - mAvatarNameCacheConnections[agent_id] = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnections.emplace(agent_id, LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2))); addObserver(agent_id_string, url, cb); return LLTrans::getString("LoadingData"); } } -LLStyle::Params LLUrlEntryAgentName::getStyle() const +LLStyle::Params LLUrlEntryAgentName::getStyle(const std::string &url) const { // don't override default colors return LLStyle::Params().is_link(false); @@ -967,9 +1002,9 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa } } -LLStyle::Params LLUrlEntryGroup::getStyle() const +LLStyle::Params LLUrlEntryGroup::getStyle(const std::string &url) const { - LLStyle::Params style_params = LLUrlEntryBase::getStyle(); + LLStyle::Params style_params = LLUrlEntryBase::getStyle(url); style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); return style_params; @@ -1045,7 +1080,6 @@ std::string LLUrlEntryChat::getLabel(const std::string &url, const LLUrlLabelCal } // LLUrlEntryParcel statics. -LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null); LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null); LLHost LLUrlEntryParcel::sRegionHost; bool LLUrlEntryParcel::sDisconnected(false); @@ -1379,17 +1413,17 @@ std::string LLUrlEntrySLLabel::getTooltip(const std::string &string) const return LLUrlEntryBase::getTooltip(string); } -bool LLUrlEntrySLLabel::underlineOnHoverOnly(const std::string &string) const +LLStyle::EUnderlineLink LLUrlEntrySLLabel::getUnderline(const std::string& string) const { std::string url = getUrl(string); - LLUrlMatch match; + LLUrlMatch match; if (LLUrlRegistry::instance().findUrl(url, match)) { - return match.underlineOnHoverOnly(); + return match.getUnderline(); } // unrecognized URL? should not happen - return LLUrlEntryBase::underlineOnHoverOnly(string); + return LLUrlEntryBase::getUnderline(string); } // @@ -1453,7 +1487,7 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC return getUrl(url); } -LLStyle::Params LLUrlEntryNoLink::getStyle() const +LLStyle::Params LLUrlEntryNoLink::getStyle(const std::string &url) const { // Don't render as URL (i.e. no context menu or hand cursor). return LLStyle::Params().is_link(false); diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 84ff278942..6e7d2fc80f 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -85,7 +85,7 @@ public: virtual std::string getIcon(const std::string &url); /// Return the style to render the displayed text - virtual LLStyle::Params getStyle() const; + virtual LLStyle::Params getStyle(const std::string &url) const; /// Given a matched Url, return a tooltip string for the hyperlink virtual std::string getTooltip(const std::string &string) const { return mTooltip; } @@ -96,12 +96,14 @@ public: /// Return the name of a SL location described by this Url, if any virtual std::string getLocation(const std::string &url) const { return ""; } - /// Should this link text be underlined only when mouse is hovered over it? - virtual bool underlineOnHoverOnly(const std::string &string) const { return false; } + virtual LLStyle::EUnderlineLink getUnderline(const std::string& string) const { return LLStyle::EUnderlineLink::UNDERLINE_ALWAYS; } virtual bool isTrusted() const { return false; } + virtual bool getSkipProfileIcon(const std::string& string) const { return false; } + virtual LLUUID getID(const std::string &string) const { return LLUUID::null; } + virtual bool isAgentID(const std::string& url) const { return false; } bool isLinkDisabled() const; @@ -109,6 +111,8 @@ public: virtual bool isSLURLvalid(const std::string &url) const { return true; }; + static void setAgentID(const LLUUID& id) { sAgentID = id; } + protected: std::string getIDStringFromUrl(const std::string &url) const; std::string escapeUrl(const std::string &url) const; @@ -130,6 +134,8 @@ protected: std::string mMenuName; std::string mTooltip; std::multimap<std::string, LLUrlEntryObserver> mObservers; + + static LLUUID sAgentID; }; /// @@ -224,19 +230,36 @@ public: /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); /*virtual*/ std::string getIcon(const std::string &url); /*virtual*/ std::string getTooltip(const std::string &string) const; - /*virtual*/ LLStyle::Params getStyle() const; + /*virtual*/ LLStyle::Params getStyle(const std::string &url) const; /*virtual*/ LLUUID getID(const std::string &string) const; - /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; + + bool isAgentID(const std::string& url) const; + + LLStyle::EUnderlineLink getUnderline(const std::string& string) const; + protected: /*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon); private: void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); - typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; + typedef std::multimap<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; /// +/// LLUrlEntryAgentMention Describes a chat mention Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/mention +class LLUrlEntryAgentMention : public LLUrlEntryAgent +{ +public: + LLUrlEntryAgentMention(); + + LLStyle::Params getStyle(const std::string& url) const; + LLStyle::EUnderlineLink getUnderline(const std::string& string) const; + bool getSkipProfileIcon(const std::string& string) const { return true; }; +}; + +/// /// LLUrlEntryAgentName Describes a Second Life agent name Url, e.g., /// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username) /// that displays various forms of user name @@ -257,14 +280,14 @@ public: mAvatarNameCacheConnections.clear(); } /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ LLStyle::Params getStyle() const; + /*virtual*/ LLStyle::Params getStyle(const std::string &url) const; protected: // override this to pull out relevant name fields virtual std::string getName(const LLAvatarName& avatar_name) = 0; private: void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); - typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; + typedef std::multimap<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t; avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; @@ -339,7 +362,7 @@ class LLUrlEntryGroup : public LLUrlEntryBase public: LLUrlEntryGroup(); /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ LLStyle::Params getStyle() const; + /*virtual*/ LLStyle::Params getStyle(const std::string &url) const; /*virtual*/ LLUUID getID(const std::string &string) const; private: void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group); @@ -411,17 +434,15 @@ public: // Processes parcel label and triggers notifying observers. static void processParcelInfo(const LLParcelData& parcel_data); - // Next 4 setters are used to update agent and viewer connection information + // Next setters are used to update agent and viewer connection information // upon events like user login, viewer disconnect and user changing region host. // These setters are made public to be accessible from newview and should not be // used in other cases. - static void setAgentID(const LLUUID& id) { sAgentID = id; } static void setSessionID(const LLUUID& id) { sSessionID = id; } static void setRegionHost(const LLHost& host) { sRegionHost = host; } static void setDisconnected(bool disconnected) { sDisconnected = disconnected; } private: - static LLUUID sAgentID; static LLUUID sSessionID; static LLHost sRegionHost; static bool sDisconnected; @@ -486,7 +507,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; + LLStyle::EUnderlineLink getUnderline(const std::string& string) const; }; /// @@ -510,7 +531,7 @@ public: LLUrlEntryNoLink(); /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ LLStyle::Params getStyle() const; + /*virtual*/ LLStyle::Params getStyle(const std::string &url) const; }; /// diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp index bfa3b167b1..f093934ca9 100644 --- a/indra/llui/llurlmatch.cpp +++ b/indra/llui/llurlmatch.cpp @@ -37,8 +37,9 @@ LLUrlMatch::LLUrlMatch() : mIcon(""), mMenuName(""), mLocation(""), - mUnderlineOnHoverOnly(false), - mTrusted(false) + mUnderline(e_underline::UNDERLINE_ALWAYS), + mTrusted(false), + mSkipProfileIcon(false) { } @@ -46,7 +47,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std const std::string& query, const std::string &tooltip, const std::string &icon, const LLStyle::Params& style, const std::string &menu, const std::string &location, - const LLUUID& id, bool underline_on_hover_only, bool trusted) + const LLUUID& id, e_underline underline, bool trusted, bool skip_icon) { mStart = start; mEnd = end; @@ -60,6 +61,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std mMenuName = menu; mLocation = location; mID = id; - mUnderlineOnHoverOnly = underline_on_hover_only; + mUnderline = underline; mTrusted = trusted; + mSkipProfileIcon = skip_icon; } diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h index ba822fbda6..418a21f963 100644 --- a/indra/llui/llurlmatch.h +++ b/indra/llui/llurlmatch.h @@ -31,7 +31,6 @@ //#include "linden_common.h" #include <string> -#include <vector> #include "llstyle.h" /// @@ -80,18 +79,20 @@ public: /// return the SL location that this Url describes, or "" if none. std::string getLocation() const { return mLocation; } - /// Should this link text be underlined only when mouse is hovered over it? - bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; } + typedef LLStyle::EUnderlineLink e_underline; + e_underline getUnderline() const { return mUnderline; } /// Return true if Url is trusted. bool isTrusted() const { return mTrusted; } + bool getSkipProfileIcon() const { return mSkipProfileIcon; } + /// 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& query, const std::string &tooltip, const std::string &icon, const LLStyle::Params& style, const std::string &menu, const std::string &location, const LLUUID& id, - bool underline_on_hover_only = false, bool trusted = false); + e_underline underline = e_underline::UNDERLINE_ALWAYS, bool trusted = false, bool skip_icon = false); const LLUUID& getID() const { return mID; } private: @@ -106,8 +107,9 @@ private: std::string mLocation; LLUUID mID; LLStyle::Params mStyle; - bool mUnderlineOnHoverOnly; + e_underline mUnderline; bool mTrusted; + bool mSkipProfileIcon; }; #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index cec1ddfc57..cb101d325d 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -62,6 +62,8 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntryAgentUserName()); // LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since // LLUrlEntryAgent is a less specific (catchall for agent urls) + mUrlEntryAgentMention = new LLUrlEntryAgentMention(); + registerUrl(mUrlEntryAgentMention); registerUrl(new LLUrlEntryAgent()); registerUrl(new LLUrlEntryChat()); registerUrl(new LLUrlEntryGroup()); @@ -155,7 +157,7 @@ static bool stringHasUrl(const std::string &text) text.find("@") != std::string::npos); } -bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted) +bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted, bool skip_non_mentions) { // avoid costly regexes if there is clearly no URL in the text if (! stringHasUrl(text)) @@ -176,6 +178,11 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL continue; } + if (skip_non_mentions && (mUrlEntryAgentMention != *it)) + { + continue; + } + LLUrlEntryBase *url_entry = *it; U32 start = 0, end = 0; @@ -233,12 +240,13 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL match_entry->getQuery(url), match_entry->getTooltip(url), match_entry->getIcon(url), - match_entry->getStyle(), + match_entry->getStyle(url), match_entry->getMenuName(), match_entry->getLocation(url), match_entry->getID(url), - match_entry->underlineOnHoverOnly(url), - match_entry->isTrusted()); + match_entry->getUnderline(url), + match_entry->isTrusted(), + match_entry->getSkipProfileIcon(url)); return true; } @@ -274,7 +282,9 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr match.getMenuName(), match.getLocation(), match.getID(), - match.underlineOnHoverOnly()); + match.getUnderline(), + false, + match.getSkipProfileIcon()); return true; } return false; @@ -317,3 +327,30 @@ void LLUrlRegistry::setKeybindingHandler(LLKeyBindingToStringHandler* handler) LLUrlEntryKeybinding *entry = (LLUrlEntryKeybinding*)mUrlEntryKeybinding; entry->setHandler(handler); } + +bool LLUrlRegistry::containsAgentMention(const std::string& text) +{ + // avoid costly regexes if there is clearly no URL in the text + if (!stringHasUrl(text)) + { + return false; + } + + try + { + boost::sregex_iterator it(text.begin(), text.end(), mUrlEntryAgentMention->getPattern()); + boost::sregex_iterator end; + for (; it != end; ++it) + { + if (mUrlEntryAgentMention->isAgentID(it->str())) + { + return true; + } + } + } + catch (boost::regex_error&) + { + LL_INFOS() << "Regex error for: " << text << LL_ENDL; + } + return false; +} diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h index 64cfec3960..592e422487 100644 --- a/indra/llui/llurlregistry.h +++ b/indra/llui/llurlregistry.h @@ -34,7 +34,6 @@ #include "llstring.h" #include <string> -#include <vector> class LLKeyBindingToStringHandler; @@ -76,7 +75,7 @@ public: /// your callback is invoked if the matched Url's label changes in the future bool findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback, - bool is_content_trusted = false); + bool is_content_trusted = false, bool skip_non_mentions = false); /// a slightly less efficient version of findUrl for wide strings bool findUrl(const LLWString &text, LLUrlMatch &match, @@ -93,6 +92,8 @@ public: // Set handler for url registry to be capable of parsing and populating keybindings void setKeybindingHandler(LLKeyBindingToStringHandler* handler); + bool containsAgentMention(const std::string& text); + private: std::vector<LLUrlEntryBase *> mUrlEntry; LLUrlEntryBase* mUrlEntryTrusted; @@ -102,6 +103,7 @@ private: LLUrlEntryBase* mUrlEntrySLLabel; LLUrlEntryBase* mUrlEntryNoLink; LLUrlEntryBase* mUrlEntryKeybinding; + LLUrlEntryBase* mUrlEntryAgentMention; }; #endif diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index f2a1e16aad..7d6c937b85 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1080,31 +1080,12 @@ bool LLView::handleUnicodeChar(llwchar uni_char, bool called_from_parent) return handled; } -bool LLView::handleUnicodeString(char *uni_str, bool editing, bool called_from_parent) -{ - auto handled = FALSE; - - if (getVisible() && getEnabled() && !handled) { - handled = handleUnicodeStringHere(uni_str, editing); - if (handled && LLView::sDebugKeys) - LL_INFOS() << "Unicode key handled by " << getName() << LL_ENDL; - } - - if (!handled && !called_from_parent && mParentView) - handled = mParentView->handleUnicodeString(uni_str, editing, FALSE); - - return handled; -} bool LLView::handleUnicodeCharHere(llwchar uni_char ) { return false; } -bool LLView::handleUnicodeStringHere(char *uni_str, bool editing) -{ - return FALSE; -} bool LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 876bfafaa3..97212a9d2d 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -54,17 +54,17 @@ class LLSD; -const U32 FOLLOWS_NONE = 0x00; -const U32 FOLLOWS_LEFT = 0x01; -const U32 FOLLOWS_RIGHT = 0x02; -const U32 FOLLOWS_TOP = 0x10; -const U32 FOLLOWS_BOTTOM = 0x20; -const U32 FOLLOWS_ALL = 0x33; +constexpr U32 FOLLOWS_NONE = 0x00; +constexpr U32 FOLLOWS_LEFT = 0x01; +constexpr U32 FOLLOWS_RIGHT = 0x02; +constexpr U32 FOLLOWS_TOP = 0x10; +constexpr U32 FOLLOWS_BOTTOM = 0x20; +constexpr U32 FOLLOWS_ALL = 0x33; -const bool MOUSE_OPAQUE = true; -const bool NOT_MOUSE_OPAQUE = false; +constexpr bool MOUSE_OPAQUE = true; +constexpr bool NOT_MOUSE_OPAQUE = false; -const U32 GL_NAME_UI_RESERVED = 2; +constexpr U32 GL_NAME_UI_RESERVED = 2; // maintains render state during traversal of UI tree @@ -241,7 +241,7 @@ public: void setUseBoundingRect( bool use_bounding_rect ); bool getUseBoundingRect() const; - ECursorType getHoverCursor() { return mHoverCursor; } + ECursorType getHoverCursor() const { return mHoverCursor; } static F32 getTooltipTimeout(); virtual const std::string getToolTip() const; @@ -265,7 +265,7 @@ public: void setDefaultTabGroup(S32 d) { mDefaultTabGroup = d; } S32 getDefaultTabGroup() const { return mDefaultTabGroup; } - S32 getLastTabGroup() { return mLastTabGroup; } + S32 getLastTabGroup() const { return mLastTabGroup; } bool isInVisibleChain() const; bool isInEnabledChain() const; @@ -385,7 +385,6 @@ public: /* virtual */ bool handleKey(KEY key, MASK mask, bool called_from_parent); /* virtual */ bool handleKeyUp(KEY key, MASK mask, bool called_from_parent); /* virtual */ bool handleUnicodeChar(llwchar uni_char, bool called_from_parent); - /* virtual */ bool handleUnicodeString(char *uni_str, bool editing, bool called_from_parent); virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, EDragAndDropType cargo_type, @@ -519,7 +518,6 @@ public: virtual bool handleKeyHere(KEY key, MASK mask); virtual bool handleKeyUpHere(KEY key, MASK mask); virtual bool handleUnicodeCharHere(llwchar uni_char); - virtual bool handleUnicodeStringHere(char *uni_str, bool editing); virtual void handleReshape(const LLRect& rect, bool by_user); virtual void dirtyRect(); diff --git a/indra/llui/llviewborder.h b/indra/llui/llviewborder.h index 1f118a0d20..a4bb748b77 100644 --- a/indra/llui/llviewborder.h +++ b/indra/llui/llviewborder.h @@ -92,7 +92,6 @@ public: private: void drawOnePixelLines(); void drawTwoPixelLines(); - void drawTextures(); EBevel mBevel; EStyle mStyle; diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp index e5e0545dad..6d907d7e45 100644 --- a/indra/llui/llviewereventrecorder.cpp +++ b/indra/llui/llviewereventrecorder.cpp @@ -261,7 +261,7 @@ void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) { event.insert("event",LLSD("keyDown")); - LL_DEBUGS() << "[VITA] unicode key: " << uni_char << LL_ENDL; + LL_DEBUGS() << "[VITA] unicode key: " << (int)uni_char << LL_ENDL; LL_DEBUGS() << "[VITA] dumpxml " << LLSDXMLStreamer(event) << "\n" << LL_ENDL; diff --git a/indra/llui/llviewereventrecorder.h b/indra/llui/llviewereventrecorder.h index 9e752e8090..5636c068d8 100644 --- a/indra/llui/llviewereventrecorder.h +++ b/indra/llui/llviewereventrecorder.h @@ -61,7 +61,7 @@ public: std::string get_xui(); void update_xui(std::string xui); - bool getLoggingStatus(){return logEvents;}; + bool getLoggingStatus() const { return logEvents; } void setEventLoggingOn(); void setEventLoggingOff(); diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp index 93106b344f..35963c2b99 100644 --- a/indra/llui/llviewmodel.cpp +++ b/indra/llui/llviewmodel.cpp @@ -82,11 +82,20 @@ void LLTextViewModel::setValue(const LLSD& value) // approximate LLSD storage usage LLViewModel::setValue(value); mDisplay = utf8str_to_wstring(mStringValue = value.asString()); + mDisplayGeneration++; // mDisplay and mValue agree mUpdateFromDisplay = false; } +LLWString& LLTextViewModel::getEditableDisplay() +{ + mDirty = true; + mDisplayGeneration++; + mUpdateFromDisplay = true; + return mDisplay; +} + void LLTextViewModel::setDisplay(const LLWString& value) { // This is the strange way to alter the value. Normally we'd setValue() @@ -94,6 +103,7 @@ void LLTextViewModel::setDisplay(const LLWString& value) // value. But a text editor might want to edit the display string // directly, then convert back to UTF8 on commit. mDisplay = value; + mDisplayGeneration++; mDirty = true; // Don't immediately convert to UTF8 -- do it lazily -- we expect many // more setDisplay() calls than getValue() calls. Just flag that it needs diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h index 6cf2200a81..16b0800ce2 100644 --- a/indra/llui/llviewmodel.h +++ b/indra/llui/llviewmodel.h @@ -105,7 +105,8 @@ public: // New functions /// Get the stored value in string form const LLWString& getDisplay() const { return mDisplay; } - LLWString& getEditableDisplay() { mDirty = true; mUpdateFromDisplay = true; return mDisplay; } + S32 getDisplayGeneration() const { return mDisplayGeneration; } + LLWString& getEditableDisplay(); /** * Set the display string directly (see LLTextEditor). What the user is @@ -120,6 +121,7 @@ private: /// To avoid converting every widget's stored value from LLSD to LLWString /// every frame, cache the converted value LLWString mDisplay; + S32 mDisplayGeneration = -1; /// As the user edits individual characters (setDisplay()), defer /// LLWString-to-UTF8 conversions until s/he's done. diff --git a/indra/llui/llvirtualtrackball.h b/indra/llui/llvirtualtrackball.h index 61a78b2398..fbfda04585 100644 --- a/indra/llui/llvirtualtrackball.h +++ b/indra/llui/llvirtualtrackball.h @@ -78,20 +78,20 @@ public: }; - virtual ~LLVirtualTrackball(); - /*virtual*/ bool postBuild(); + ~LLVirtualTrackball() override; + bool postBuild() override; - virtual bool handleHover(S32 x, S32 y, MASK mask); - virtual bool handleMouseUp(S32 x, S32 y, MASK mask); - virtual bool handleMouseDown(S32 x, S32 y, MASK mask); - virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual bool handleKeyHere(KEY key, MASK mask); + bool handleHover(S32 x, S32 y, MASK mask) override; + bool handleMouseUp(S32 x, S32 y, MASK mask) override; + bool handleMouseDown(S32 x, S32 y, MASK mask) override; + bool handleRightMouseDown(S32 x, S32 y, MASK mask) override; + bool handleKeyHere(KEY key, MASK mask) override; - virtual void draw(); + void draw() override; - virtual void setValue(const LLSD& value); - void setValue(F32 x, F32 y, F32 z, F32 w); - virtual LLSD getValue() const; + void setValue(const LLSD& value) override; + void setValue(F32 x, F32 y, F32 z, F32 w); + LLSD getValue() const override; void setRotation(const LLQuaternion &value); LLQuaternion getRotation() const; @@ -102,7 +102,6 @@ public: protected: friend class LLUICtrlFactory; LLVirtualTrackball(const Params&); - void onEditChange(); protected: LLTextBox* mNLabel; diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h index da29188943..ee230cd2f6 100644 --- a/indra/llui/llwindowshade.h +++ b/indra/llui/llwindowshade.h @@ -49,7 +49,7 @@ public: }; void show(LLNotificationPtr); - /*virtual*/ void draw(); + void draw() override; void hide(); bool isShown() const; diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp index 8fd85a89a1..8cd11b86b3 100644 --- a/indra/llui/llxuiparser.cpp +++ b/indra/llui/llxuiparser.cpp @@ -30,7 +30,7 @@ #include "llxmlnode.h" #include "llfasttimer.h" -#ifdef LL_USESYSTEMLIBS +#if 1 #include <expat.h> #else #include "expat/expat.h" diff --git a/indra/llui/llxyvector.h b/indra/llui/llxyvector.h index bc41213c13..646771f387 100644 --- a/indra/llui/llxyvector.h +++ b/indra/llui/llxyvector.h @@ -65,18 +65,18 @@ public: }; - virtual ~LLXYVector(); - /*virtual*/ bool postBuild(); + ~LLXYVector() override; + bool postBuild() override; - virtual bool handleHover(S32 x, S32 y, MASK mask); - virtual bool handleMouseUp(S32 x, S32 y, MASK mask); - virtual bool handleMouseDown(S32 x, S32 y, MASK mask); + bool handleHover(S32 x, S32 y, MASK mask) override; + bool handleMouseUp(S32 x, S32 y, MASK mask) override; + bool handleMouseDown(S32 x, S32 y, MASK mask) override; - virtual void draw(); + void draw() override; - virtual void setValue(const LLSD& value); - void setValue(F32 x, F32 y); - virtual LLSD getValue() const; + void setValue(const LLSD& value) override; + void setValue(F32 x, F32 y); + LLSD getValue() const override; protected: friend class LLUICtrlFactory; |