diff options
Diffstat (limited to 'indra/llui')
75 files changed, 862 insertions, 238 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 908e94b24c..83b3a220a0 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -272,6 +272,8 @@ target_link_libraries(llui llcommon ) +include(LibraryInstall) + # Add tests if(LL_TESTS) include(LLAddBuildTest) diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 495ba2f40f..ac8f7c2126 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -47,6 +47,8 @@ static constexpr F32 AUTO_SCROLL_RATE_ACCEL = 120.f; static LLDefaultChildRegistry::Register<LLAccordionCtrl> t2("accordion"); +std::set<LLAccordionCtrl*> LLAccordionCtrl::sPendingArrange; + LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) , mFitParent(params.fit_parent) , mNoVisibleTabsOrigString(params.no_visible_tabs_text.initial_value().asString()) @@ -163,7 +165,11 @@ bool LLAccordionCtrl::postBuild() //--------------------------------------------------------------------------------- LLAccordionCtrl::~LLAccordionCtrl() { - mAccordionTabs.clear(); + if (mArrangePending) + { + sPendingArrange.erase(this); + } + mAccordionTabs.clear(); } //--------------------------------------------------------------------------------- @@ -184,7 +190,7 @@ void LLAccordionCtrl::reshape(S32 width, S32 height, bool called_from_parent) // necessary text paddings can be set via h_pad and v_pad mNoVisibleTabsHelpText->setRect(getLocalRect()); - arrange(); + scheduleArrange(); } //--------------------------------------------------------------------------------- @@ -325,7 +331,7 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLAccordionCtrlTab* accordion_tab) mAccordionTabs.push_back(accordion_tab); accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, (S16)(mAccordionTabs.size() - 1)) ); - arrange(); + scheduleArrange(); } void LLAccordionCtrl::removeCollapsibleCtrl(LLAccordionCtrlTab* accordion_tab) @@ -494,6 +500,7 @@ void LLAccordionCtrl::arrangeMultiple() void LLAccordionCtrl::arrange() { + LL_PROFILE_ZONE_SCOPED; updateNoTabsHelpTextVisibility(); if (mAccordionTabs.empty()) @@ -681,8 +688,9 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) std::string str_action = info["action"]; if (str_action == "size_changes") { - // - arrange(); + // Multiple children can request an arrange, + // but only need to do it once so schedule it for later. + scheduleArrange(); return 1; } if (str_action == "select_next") @@ -924,3 +932,25 @@ void LLAccordionCtrl::collapseAllTabs() arrange(); } } + +void LLAccordionCtrl::scheduleArrange() +{ + if (!mArrangePending) + { + mArrangePending = true; + sPendingArrange.insert(this); + } +} + +void LLAccordionCtrl::updateClass() +{ + for (LLAccordionCtrl* inst : sPendingArrange) + { + if (inst) + { + inst->mArrangePending = false; + inst->arrange(); + } + } + sPendingArrange.clear(); +} diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index 43a33a2b3c..c7bb8bc9ff 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -142,6 +142,9 @@ public: void setSkipScrollToChild(bool skip) { mSkipScrollToChild = skip; } + void scheduleArrange(); + static void updateClass(); + private: void initNoTabsWidget(const LLTextBox::Params& tb_params); void updateNoTabsHelpTextVisibility(); @@ -188,12 +191,15 @@ private: LLTextBox* mNoVisibleTabsHelpText = nullptr; bool mSkipScrollToChild = false; + bool mArrangePending = false; std::string mNoMatchedTabsOrigString; std::string mNoVisibleTabsOrigString; LLAccordionCtrlTab* mSelectedTab = nullptr; const LLTabComparator* mTabComparator = nullptr; + + static std::set<LLAccordionCtrl*> sPendingArrange; }; diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index ac66525030..828bfb289b 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -248,10 +248,22 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw() void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, bool called_from_parent /* = true */) { S32 header_height = mHeaderTextbox->getTextPixelHeight(); + LLRect old_header_rect = mHeaderTextbox->getRect(); LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET, (height + header_height) / 2, width, (height - header_height) / 2); - mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight()); - mHeaderTextbox->setRect(textboxRect); + if (old_header_rect.getHeight() != textboxRect.getHeight() + || old_header_rect.mLeft != textboxRect.mLeft + || old_header_rect.mTop != textboxRect.mTop + || old_header_rect.getWidth() > textboxRect.getWidth() // reducing header's width + || (old_header_rect.getWidth() < textboxRect.getWidth() && old_header_rect.getWidth() < mHeaderTextbox->getTextPixelWidth())) + { + // Expensive text reflow + // Update if position or height changes + // Update if width reduces + // But do not update if text already fits and width increases (arguably LLTextBox::reshape should be smarter, not Accordion) + mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight()); + mHeaderTextbox->setRect(textboxRect); + } if (mHeaderTextbox->getTextPixelWidth() > mHeaderTextbox->getRect().getWidth()) { @@ -416,8 +428,11 @@ void LLAccordionCtrlTab::reshape(S32 width, S32 height, bool called_from_parent LLRect headerRect; headerRect.setLeftTopAndSize(0, height, width, HEADER_HEIGHT); - mHeader->setRect(headerRect); - mHeader->reshape(headerRect.getWidth(), headerRect.getHeight()); + if (mHeader->getRect() != headerRect) + { + mHeader->setRect(headerRect); + mHeader->reshape(headerRect.getWidth(), headerRect.getHeight()); + } if (!mDisplayChildren) return; @@ -464,7 +479,34 @@ void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl) // Translate to parent coordinatess to check if we are in visible rectangle rect.translate(getRect().mLeft, getRect().mBottom); - if (!getRect().contains(rect)) + bool needs_to_scroll = false; + const LLRect &acc_rect = getRect(); + if (!acc_rect.contains(rect)) + { + if (acc_rect.mTop < rect.mBottom || acc_rect.mBottom > rect.mTop) + { + // Content fully not in view + needs_to_scroll = true; + } + else if (acc_rect.getHeight() >= rect.getHeight()) + { + // Content can be displayed fully, but only partially in view + needs_to_scroll = true; + } + else if (acc_rect.mTop <= rect.mTop || acc_rect.mBottom >= rect.mBottom) + { + // Intersects, but too big to be displayed fully + S32 covered_height = acc_rect.mTop > rect.mTop ? rect.mTop - acc_rect.mBottom : acc_rect.mTop - rect.mBottom; + constexpr F32 covered_ratio = 0.7f; + if (covered_height < covered_ratio * acc_rect.getHeight()) + { + // Try to show bigger portion of the content + needs_to_scroll = true; + } + } + // else too big and in the middle of the view as is + } + if (needs_to_scroll) { // for accordition's scroll, height is in pixels // Back to local coords and calculate position for scroller @@ -932,7 +974,7 @@ void LLAccordionCtrlTab::adjustContainerPanel(const LLRect& child_rect) show_hide_scrollbar(child_rect); updateLayout(child_rect); } - else + else if (mContainerPanel->getRect() != child_rect) { mContainerPanel->reshape(child_rect.getWidth(), child_rect.getHeight()); mContainerPanel->setRect(child_rect); diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 3fdcf9f7f2..bb0b8ce04f 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -140,7 +140,7 @@ public: S32 notify(const LLSD& info); bool notifyChildren(const LLSD& info); - void draw(); + virtual void draw(); void storeOpenCloseState(); void restoreOpenCloseState(); diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index d2534b3939..0048c44189 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -190,7 +190,7 @@ LLButton::LLButton(const LLButton::Params& p) // Note: flashing should be allowed in settings.xml (boolean key "EnableButtonFlashing"). S32 flash_count = p.button_flash_count.isProvided()? p.button_flash_count : 0; F32 flash_rate = p.button_flash_rate.isProvided()? p.button_flash_rate : 0.0f; - mFlashingTimer = new LLFlashTimer ((LLFlashTimer::callback_t)NULL, flash_count, flash_rate); + mFlashingTimer = new LLFlashTimer((LLFlashTimer::callback_t) nullptr, flash_count, flash_rate); } else { diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 890e7c2d1e..f530eceb4b 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -153,7 +153,7 @@ public: ~LLButton(); // For backward compatability only - typedef boost::function<void(void*)> button_callback_t; + typedef std::function<void(void*)> button_callback_t; void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName, const LLUUID& imageID,const std::string& xmlTagName) const; diff --git a/indra/llui/llcallbackmap.h b/indra/llui/llcallbackmap.h index 07775dc30f..3115606d91 100644 --- a/indra/llui/llcallbackmap.h +++ b/indra/llui/llcallbackmap.h @@ -29,13 +29,13 @@ #include <map> #include <string> -#include <boost/function.hpp> +#include <functional> class LLCallbackMap { public: // callback definition. - typedef boost::function<void* (void* data)> callback_t; + typedef std::function<void* (void* data)> callback_t; typedef std::map<std::string, LLCallbackMap> map_t; typedef map_t::iterator map_iter_t; @@ -48,8 +48,8 @@ public: return (void*)panel; } - LLCallbackMap() : mCallback(NULL), mData(NULL) { } - LLCallbackMap(callback_t callback, void* data = NULL) : mCallback(callback), mData(data) { } + LLCallbackMap() : mCallback(nullptr), mData(nullptr) {} + LLCallbackMap(callback_t callback, void* data = nullptr) : mCallback(callback), mData(data) {} callback_t mCallback; void* mData; diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 12d8233e0a..9f9cc3e54d 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -27,8 +27,6 @@ #ifndef LL_LLCLIPBOARD_H #define LL_LLCLIPBOARD_H -#include <boost/function.hpp> - #include "llstring.h" #include "lluuid.h" #include "llsingleton.h" diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index f3876ef695..ae676251ff 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -1009,7 +1009,7 @@ void LLComboBox::setKeystrokeOnEsc(bool enable) void LLComboBox::onTextEntry(LLLineEditor* line_editor) { - if (mTextEntryCallback != NULL) + if (mTextEntryCallback != nullptr) { (mTextEntryCallback)(line_editor, LLSD()); } @@ -1029,7 +1029,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor) mList->deselectAllItems(); mLastSelectedIndex = -1; } - if (mTextChangedCallback != NULL) + if (mTextChangedCallback != nullptr) { (mTextChangedCallback)(line_editor, LLSD()); } @@ -1077,7 +1077,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor) // RN: presumably text entry updateSelection(); } - if (mTextChangedCallback != NULL) + if (mTextChangedCallback != nullptr) { (mTextChangedCallback)(line_editor, LLSD()); } diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 8be3eb57e4..d6ea1202d3 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -36,7 +36,6 @@ #include "llrect.h" #include "llscrolllistctrl.h" #include "lllineeditor.h" -#include <boost/function.hpp> // Classes diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 19ae03cdf9..c20e5a806c 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -77,7 +77,7 @@ LLDockableFloater::~LLDockableFloater() bool LLDockableFloater::postBuild() { // Remember we should force docking when the floater is opened for the first time - if (mIsDockedStateForcedCallback != NULL && mIsDockedStateForcedCallback()) + if (mIsDockedStateForcedCallback != nullptr && mIsDockedStateForcedCallback()) { mForceDocking = true; } diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index 9c516e23a4..accd9fddfc 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -129,7 +129,7 @@ protected: // Checks if docking should be forced. // It may be useful e.g. if floater created in mouselook mode (see EXT-5609) - boost::function<bool ()> mIsDockedStateForcedCallback; + std::function<bool()> mIsDockedStateForcedCallback; private: std::unique_ptr<LLDockControl> mDockControl; diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h index b6ac9c19dd..1f6c3b9f57 100644 --- a/indra/llui/lldockcontrol.h +++ b/indra/llui/lldockcontrol.h @@ -49,11 +49,11 @@ public: public: // callback for a function getting a rect valid for control's position - typedef boost::function<void (LLRect& )> get_allowed_rect_callback_t; + typedef std::function<void (LLRect& )> get_allowed_rect_callback_t; LOG_CLASS(LLDockControl); LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, - const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_rect_callback = NULL); + const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_rect_callback = nullptr); virtual ~LLDockControl(); public: diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index 925608e47e..16e6f0591a 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -390,14 +390,17 @@ void LLEmojiDictionary::loadEmojis() continue; } + std::string category; std::list<std::string> categories = loadCategories(sd); if (categories.empty()) { - LL_WARNS() << "Skipping invalid emoji descriptor (no categories)" << LL_ENDL; - continue; + // Should already have a localization for "other symbols" + category = "other symbols"; + } + else + { + category = categories.front(); } - - std::string category = categories.front(); if (std::find(mSkipCategories.begin(), mSkipCategories.end(), category) != mSkipCategories.end()) { diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index b2c59ce775..7cdd19bebc 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -117,7 +117,17 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight(); rect.setLeftTopAndSize(left, top, rect.getWidth(), rect.getHeight()); pHelperFloater->setRect(rect); + + // Hack: Trying to open floater, search for a match, + // and hide floater immediately if no match found, + // instead of checking prior to opening + // + // Supress sounds in case floater won't be shown. + // Todo: add some kind of shouldShow(short_code) + U8 sound_flags = pHelperFloater->getSoundFlags(); + pHelperFloater->setSoundFlags(LLView::SILENT); pHelperFloater->openFloater(LLSD().with("hint", short_code)); + pHelperFloater->setSoundFlags(sound_flags); } void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p, bool strict) diff --git a/indra/llui/llflashtimer.cpp b/indra/llui/llflashtimer.cpp index 54f54653e2..addc3375b3 100644 --- a/indra/llui/llflashtimer.cpp +++ b/indra/llui/llflashtimer.cpp @@ -50,7 +50,7 @@ LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period) void LLFlashTimer::unset() { mUnset = true; - mCallback = NULL; + mCallback = nullptr; } bool LLFlashTimer::tick() diff --git a/indra/llui/llflashtimer.h b/indra/llui/llflashtimer.h index 4ef70faf2d..1cd1df392b 100644 --- a/indra/llui/llflashtimer.h +++ b/indra/llui/llflashtimer.h @@ -28,13 +28,13 @@ #define LL_FLASHTIMER_H #include "lleventtimer.h" -#include "boost/function.hpp" +#include <functional> class LLFlashTimer : public LLEventTimer { public: - typedef boost::function<void (bool)> callback_t; + typedef std::function<void (bool)> callback_t; /** * Constructor. @@ -43,7 +43,7 @@ public: * @param period - how frequently callback should be called * @param cb - callback to be called each tick */ - LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0); + LLFlashTimer(callback_t cb = nullptr, S32 count = 0, F32 period = 0.0); ~LLFlashTimer() {}; /*virtual*/ bool tick(); diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 8178bada42..34eb1ea3fc 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -69,7 +69,7 @@ const LLRect& LLFlatListView::getItemsRect() const bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/,bool rearrange /*= true*/) { if (!item) return false; - if (value.isUndefined()) return false; + if (value.isUndefined()) return false; // item stays an orphan?!!! //force uniqueness of items, easiest check but unreliable if (item->getParent() == mItemsPanel) return false; @@ -537,6 +537,7 @@ bool LLFlatListView::postBuild() void LLFlatListView::rearrangeItems() { + LL_PROFILE_ZONE_SCOPED; static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); setNoItemsCommentVisible(0==size()); @@ -1132,6 +1133,7 @@ bool LLFlatListView::removeItemPair(item_pair_t* item_pair, bool rearrange) void LLFlatListView::notifyParentItemsRectChanged() { + LL_PROFILE_ZONE_SCOPED; S32 comment_height = 0; // take into account comment text height if exists @@ -1346,9 +1348,17 @@ bool LLFlatListViewEx::getForceShowingUnmatchedItems() const return mForceShowingUnmatchedItems; } -void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show) +void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show, bool notify_parent) +{ + if (mForceShowingUnmatchedItems != show) { mForceShowingUnmatchedItems = show; + if (!mFilterSubString.empty()) + { + updateNoItemsMessage(mFilterSubString); + filterItems(false, true); + } + } } void LLFlatListViewEx::setFilterSubString(const std::string& filter_str, bool notify_parent) @@ -1393,7 +1403,7 @@ bool LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) return false; } -void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent) +bool LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent) { std::string cur_filter = mFilterSubString; LLStringUtil::toUpper(cur_filter); @@ -1416,8 +1426,11 @@ void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent) if (visibility_changed && notify_parent) { + rearrangeItems(); notifyParentItemsRectChanged(); + return true; } + return false; } bool LLFlatListViewEx::hasMatchedItems() diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 6271231183..39afa33be8 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -484,7 +484,11 @@ public: bool getForceShowingUnmatchedItems() const; - void setForceShowingUnmatchedItems(bool show); + /** + * Sets filtered out items to stay visible. Can result in rect changes, + * so can notify_parent if rect changes + */ + void setForceShowingUnmatchedItems(bool show, bool notify_parent); /** * Sets up new filter string and filters the list. @@ -495,8 +499,9 @@ public: /** * Filters the list, rearranges and notifies parent about shape changes. * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration. + * Returns true in case of changes */ - void filterItems(bool re_sort, bool notify_parent); + bool filterItems(bool re_sort, bool notify_parent); /** * Returns true if last call of filterItems() found at least one matching item diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index fd07b2ec5d..52a5e3dbd6 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2274,7 +2274,7 @@ void LLFloater::drawConeToOwner(F32 &context_cone_opacity, LLRect local_rect = getLocalRect(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); + LLGLEnable cull_face(GL_CULL_FACE); gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity); diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index 94a67c8d8b..24d1476dda 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -30,8 +30,8 @@ #include "llrect.h" #include "llsd.h" +#include <functional> #include <list> -#include <boost/function.hpp> //******************************************************* // @@ -41,7 +41,7 @@ class LLFloater; class LLUICtrl; -typedef boost::function<LLFloater* (const LLSD& key)> LLFloaterBuildFunc; +typedef std::function<LLFloater* (const LLSD& key)> LLFloaterBuildFunc; class LLFloaterReg { diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 0d7c98294f..7544a44478 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -32,11 +32,11 @@ const F32 FOCUS_FADE_TIME = 0.3f; -LLFocusableElement::LLFocusableElement() -: mFocusLostCallback(NULL), - mFocusReceivedCallback(NULL), - mFocusChangedCallback(NULL), - mTopLostCallback(NULL) +LLFocusableElement::LLFocusableElement() : + mFocusLostCallback(nullptr), + mFocusReceivedCallback(nullptr), + mFocusChangedCallback(nullptr), + mTopLostCallback(nullptr) { } diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index b664065532..db4ab8487e 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1510,6 +1510,7 @@ bool LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) && ( count > 0 && (hasVisibleChildren()) ))) && // show menu only if selected items are visible !hide_folder_menu) { + LL_INFOS("Inventory") << "Opening inventory menu from path: " << getPathname() << LL_ENDL; if (mCallbackRegistrar) { mCallbackRegistrar->pushScope(); diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index bdce9dec54..368a86ea84 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -221,6 +221,7 @@ public: void scrollToShowSelection(); void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect); void setScrollContainer( LLScrollContainer* parent ) { mScrollContainer = parent; } + LLScrollContainer* getScrollContainer() { return mScrollContainer; } LLRect getVisibleRect(); bool search(LLFolderViewItem* first_item, const std::string &search_string, bool backward); diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 6d0cfcba95..878f1cb856 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -31,11 +31,12 @@ #include "llfolderviewitem.h" #include "llfolderview.h" #include "llfolderviewmodel.h" -#include "llpanel.h" #include "llcallbacklist.h" #include "llcriticaldamp.h" #include "llclipboard.h" #include "llfocusmgr.h" // gFocusMgr +#include "llnotificationsutil.h" +#include "llpanel.h" #include "lltrans.h" #include "llwindow.h" @@ -60,7 +61,11 @@ LLUIColor LLFolderViewItem::sSearchStatusColor; S32 LLFolderViewItem::sTopPad = 0; LLUIImagePtr LLFolderViewItem::sFolderArrowImg; LLUIImagePtr LLFolderViewItem::sSelectionImg; +LLUIImagePtr LLFolderViewItem::sFavoriteImg; +LLUIImagePtr LLFolderViewItem::sFavoriteContentImg; LLFontGL* LLFolderViewItem::sSuffixFont = nullptr; +LLUIColor LLFolderViewItem::sFavoriteColor; +bool LLFolderViewItem::sColorSetInitialized = false; // only integers can be initialized in header const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f; @@ -68,6 +73,9 @@ const F32 LLFolderViewItem::FOLDER_OPEN_TIME_CONSTANT = 0.03f; const LLColor4U DEFAULT_WHITE(255, 255, 255); +constexpr S32 FAVORITE_IMAGE_SIZE = 14; +constexpr S32 FAVORITE_IMAGE_PAD = 3; + //static LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style) @@ -102,6 +110,8 @@ void LLFolderViewItem::initClass() sTopPad = default_params.item_top_pad; sFolderArrowImg = default_params.folder_arrow_image; sSelectionImg = default_params.selection_image; + sFavoriteImg = default_params.favorite_image; + sFavoriteContentImg = default_params.favorite_content_image; sSuffixFont = getLabelFontForStyle(LLFontGL::NORMAL); sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); @@ -121,6 +131,8 @@ void LLFolderViewItem::cleanupClass() sFonts.clear(); sFolderArrowImg = nullptr; sSelectionImg = nullptr; + sFavoriteImg = nullptr; + sFavoriteContentImg = nullptr; sSuffixFont = nullptr; } @@ -129,13 +141,15 @@ void LLFolderViewItem::cleanupClass() LLFolderViewItem::Params::Params() : root(), listener(), + favorite_image("favorite_image"), + favorite_content_image("favorite_content_image"), folder_arrow_image("folder_arrow_image"), folder_indentation("folder_indentation"), selection_image("selection_image"), item_height("item_height"), item_top_pad("item_top_pad"), creation_date(), - allow_wear("allow_wear", true), + marketplace_item("marketplace_item", false), allow_drop("allow_drop", true), font_color("font_color"), font_highlight_color("font_highlight_color"), @@ -155,6 +169,8 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) : LLView(p), mLabelWidth(0), mLabelWidthDirty(false), + mIsFavorite(false), + mHasFavorites(false), mSuffixNeedsRefresh(false), mLabelPaddingRight(DEFAULT_LABEL_PADDING_RIGHT), mParentFolder( NULL ), @@ -175,7 +191,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mRoot(p.root), mViewModelItem(p.listener), mIsMouseOverTitle(false), - mAllowWear(p.allow_wear), + mMarketplaceItem(p.marketplace_item), mAllowDrop(p.allow_drop), mFontColor(p.font_color), mFontHighlightColor(p.font_highlight_color), @@ -189,6 +205,21 @@ 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); + sFavoriteColor = LLUIColorTable::instance().getColor("InventoryFavoriteColor", DEFAULT_WHITE); + sColorSetInitialized = true; + } + if (mViewModelItem) { mViewModelItem->setFolderViewItem(this); @@ -211,6 +242,7 @@ bool LLFolderViewItem::postBuild() // getDisplayName() is expensive (due to internal getLabelSuffix() and name building) // it also sets search strings so it requires a filter reset mLabel = utf8str_to_wstring(vmi->getDisplayName()); + mIsFavorite = vmi->isFavorite() && !vmi->isItemInTrash(); setToolTip(vmi->getName()); // Dirty the filter flag of the model from the view (CHUI-849) @@ -325,6 +357,7 @@ void LLFolderViewItem::refresh() mLabel = utf8str_to_wstring(vmi.getDisplayName()); mLabelFontBuffer.reset(); + mIsFavorite = vmi.isFavorite() && !vmi.isItemInTrash(); setToolTip(vmi.getName()); // icons are slightly expensive to get, can be optimized // see LLInventoryIcon::getIcon() @@ -359,6 +392,8 @@ void LLFolderViewItem::refreshSuffix() mIconOpen = vmi->getIconOpen(); mIconOverlay = vmi->getIconOverlay(); + mIsFavorite = vmi->isFavorite() && !vmi->isItemInTrash(); + if (mRoot->useLabelSuffix()) { // Very Expensive! @@ -428,6 +463,10 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height ) } mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel.c_str()) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix.c_str()) + mLabelPaddingRight; mLabelWidthDirty = false; + if (mIsFavorite) + { + mLabelWidth += FAVORITE_IMAGE_SIZE + FAVORITE_IMAGE_PAD; + } } *width = llmax(*width, mLabelWidth); @@ -554,10 +593,15 @@ void LLFolderViewItem::buildContextMenu(LLMenuGL& menu, U32 flags) void LLFolderViewItem::openItem( void ) { - if (mAllowWear || !getViewModelItem()->isItemWearable()) + if (!mMarketplaceItem || !getViewModelItem()->isItemWearable()) { getViewModelItem()->openItem(); } + else if (mMarketplaceItem) + { + // Wearing an object from any listing, active or not, is verbotten + LLNotificationsUtil::add("AlertMerchantListingCannotWear"); + } } void LLFolderViewItem::rename(const std::string& new_name) @@ -771,6 +815,45 @@ void LLFolderViewItem::drawOpenFolderArrow() } } +void LLFolderViewItem::drawFavoriteIcon() +{ + static LLUICachedControl<bool> draw_star("InventoryFavoritesUseStar", true); + static LLUICachedControl<bool> draw_hollow_star("InventoryFavoritesUseHollowStar", true); + + LLUIImage* favorite_image = nullptr; + if (draw_star && mIsFavorite) + { + favorite_image = sFavoriteImg; + } + else if (draw_hollow_star && mHasFavorites && !isOpen()) + { + favorite_image = sFavoriteContentImg; + } + + if (favorite_image) + { + S32 x_offset = 0; + LLScrollContainer* scroll = mRoot->getScrollContainer(); + if (scroll) + { + S32 width = scroll->getVisibleContentRect().getWidth(); + S32 offset = scroll->getDocPosHorizontal(); + x_offset = width + offset; + } + else + { + x_offset = getRect().getWidth(); + } + gl_draw_scaled_image( + x_offset - FAVORITE_IMAGE_SIZE - FAVORITE_IMAGE_PAD, + getRect().getHeight() - mItemHeight + FAVORITE_IMAGE_PAD, + FAVORITE_IMAGE_SIZE, + FAVORITE_IMAGE_SIZE, + favorite_image->getImage(), + sFgColor); + } +} + /*virtual*/ bool LLFolderViewItem::isHighlightAllowed() { return mIsSelected; @@ -928,6 +1011,7 @@ void LLFolderViewItem::draw() { drawOpenFolderArrow(); } + drawFavoriteIcon(); drawHighlight(show_context, filled, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor); @@ -999,7 +1083,20 @@ void LLFolderViewItem::draw() } } - LLColor4 color = (mIsSelected && filled) ? mFontHighlightColor : mFontColor; + static LLUICachedControl<bool> highlight_color("InventoryFavoritesColorText", true); + LLColor4 color; + if (mIsSelected && filled) + { + color = mFontHighlightColor; + } + else if (mIsFavorite && highlight_color) + { + color = sFavoriteColor; + } + else + { + color = mFontColor; + } if (isFadeItem()) { @@ -1093,7 +1190,8 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ): mIsFolderComplete(false), // folder might have children that are not loaded yet. mAreChildrenInited(false), // folder might have children that are not built yet. mLastArrangeGeneration( -1 ), - mLastCalculatedWidth(0) + mLastCalculatedWidth(0), + mFavoritesDirtyFlags(0) { } @@ -1119,6 +1217,11 @@ LLFolderViewFolder::~LLFolderViewFolder( void ) // The LLView base class takes care of object destruction. make sure that we // don't have mouse or keyboard focus gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() + + if (mFavoritesDirtyFlags) + { + gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, this); + } } // addToFolder() returns true if it succeeds. false otherwise @@ -1762,6 +1865,148 @@ bool LLFolderViewFolder::isMovable() return true; } +void LLFolderViewFolder::updateHasFavorites(bool new_childs_value) +{ + if (mFavoritesDirtyFlags == 0) + { + gIdleCallbacks.addFunction(&LLFolderViewFolder::onIdleUpdateFavorites, this); + } + if (new_childs_value) + { + mFavoritesDirtyFlags |= FAVORITE_ADDED; + } + else + { + mFavoritesDirtyFlags |= FAVORITE_REMOVED; + } +} + +void LLFolderViewFolder::onIdleUpdateFavorites(void* data) +{ + LLFolderViewFolder* self = reinterpret_cast<LLFolderViewFolder*>(data); + if (self->mFavoritesDirtyFlags == FAVORITE_CLEANUP) + { + // parent or child already processed the update, clean the callback + self->mFavoritesDirtyFlags = 0; + gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, data); + return; + } + + if (self->mFavoritesDirtyFlags == 0) + { + llassert(false); // should not happen, everything that sets to 0 should clean callback + gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, data); + return; + } + + if (self->getViewModelItem()->isItemInTrash()) + { + // do not display favorite-stars in trash + self->mFavoritesDirtyFlags = 0; + gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, self); + return; + } + + if (self->mFavoritesDirtyFlags == FAVORITE_ADDED) + { + if (!self->mHasFavorites) + { + // propagate up, exclude root + LLFolderViewFolder* parent = self; + while (parent + && (!parent->hasFavorites() || parent->mFavoritesDirtyFlags) + && !parent->getViewModelItem()->isAgentInventoryRoot()) + { + parent->setHasFavorites(true); + if (parent->mFavoritesDirtyFlags) + { + // Parent will remove onIdleUpdateFavorites later, don't remove now, + // We are inside gIdleCallbacks. Removing 'self' callback is safe, + // but removing 'parent' can invalidate following iterator + parent->mFavoritesDirtyFlags = FAVORITE_CLEANUP; + } + parent = parent->getParentFolder(); + } + } + else + { + // already up to date + self->mFavoritesDirtyFlags = 0; + gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, self); + } + } + else if (self->mFavoritesDirtyFlags > FAVORITE_ADDED) + { + // full check + LLFolderViewFolder* parent = self; + while (parent && !parent->getViewModelItem()->isAgentInventoryRoot()) + { + bool has_favorites = false; + for (items_t::iterator iter = parent->mItems.begin(); + iter != parent->mItems.end();) + { + items_t::iterator iit = iter++; + if ((*iit)->isFavorite()) + { + has_favorites = true; + break; + } + } + + for (folders_t::iterator iter = parent->mFolders.begin(); + iter != parent->mFolders.end() && !has_favorites;) + { + folders_t::iterator fit = iter++; + if ((*fit)->isFavorite() || (*fit)->hasFavorites()) + { + has_favorites = true; + break; + } + } + + if (!has_favorites) + { + if (parent->hasFavorites()) + { + parent->setHasFavorites(false); + } + else + { + // Nothing changed + break; + } + } + else + { + // propagate up, exclude root + while (parent + && (!parent->hasFavorites() || parent->mFavoritesDirtyFlags) + && !parent->getViewModelItem()->isAgentInventoryRoot()) + { + parent->setHasFavorites(true); + if (parent->mFavoritesDirtyFlags) + { + // Parent will remove onIdleUpdateFavorites later, don't remove now, + // We are inside gIdleCallbacks. Removing 'self' callback is safe, + // but removing 'parent' can invalidate following iterator + parent->mFavoritesDirtyFlags = FAVORITE_CLEANUP; + } + parent = parent->getParentFolder(); + } + break; + } + if (parent->mFavoritesDirtyFlags) + { + // Parent will remove onIdleUpdateFavorites later, don't remove now. + // We are inside gIdleCallbacks. Removing 'self' callback is safe, + // but removing 'parent' can invalidate following iterator + parent->mFavoritesDirtyFlags = FAVORITE_CLEANUP; + } + parent = parent->getParentFolder(); + } + } +} + bool LLFolderViewFolder::isRemovable() { @@ -1869,10 +2114,14 @@ void LLFolderViewFolder::setOpen(bool openitem) { // navigateToFolder can destroy this view // delay it in case setOpen was called from click or key processing - doOnIdleOneTime([this]() - { - getViewModelItem()->navigateToFolder(); - }); + LLPointer<LLFolderViewModelItem> view_model_item = mViewModelItem; + doOnIdleOneTime([view_model_item]() + { + if (view_model_item.notNull()) + { + view_model_item.get()->navigateToFolder(); + } + }); } else { diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 2ee018a90a..23d794bf26 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -50,7 +50,9 @@ class LLFolderViewItem : public LLView public: struct Params : public LLInitParam::Block<Params, LLView::Params> { - Optional<LLUIImage*> folder_arrow_image, + Optional<LLUIImage*> favorite_image, + favorite_content_image, + folder_arrow_image, selection_image; Mandatory<LLFolderView*> root; Mandatory<LLFolderViewModelItem*> listener; @@ -60,7 +62,7 @@ public: item_top_pad; Optional<time_t> creation_date; - Optional<bool> allow_wear; + Optional<bool> marketplace_item; Optional<bool> allow_drop; Optional<LLUIColor> font_color; @@ -93,6 +95,8 @@ protected: LLWString mLabel; S32 mLabelWidth; bool mLabelWidthDirty; + bool mIsFavorite; + bool mHasFavorites; S32 mLabelPaddingRight; LLFolderViewFolder* mParentFolder; LLPointer<LLFolderViewModelItem> mViewModelItem; @@ -122,7 +126,7 @@ protected: mIsCurSelection, mDragAndDropTarget, mIsMouseOverTitle, - mAllowWear, + mMarketplaceItem, mAllowDrop, mSingleFolderMode, mDoubleClickOverride, @@ -133,6 +137,7 @@ protected: LLUIColor mFontColor; LLUIColor mFontHighlightColor; + static bool sColorSetInitialized; // For now assuming all colors are the same in derived classes. static LLUIColor sFgColor; @@ -145,6 +150,8 @@ protected: static LLUIColor sFilterTextColor; static LLUIColor sSuffixColor; static LLUIColor sSearchStatusColor; + static LLUIColor sFavoriteColor; + // this is an internal method used for adding items to folders. A // no-op at this level, but reimplemented in derived classes. @@ -208,6 +215,8 @@ public: // Returns true is this object and all of its children can be moved virtual bool isMovable(); + bool isFavorite() const { return mIsFavorite; } + // destroys this item recursively virtual void destroyView(); @@ -298,6 +307,7 @@ public: // virtual void handleDropped(); virtual void draw(); void drawOpenFolderArrow(); + void drawFavoriteIcon(); 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, @@ -311,6 +321,8 @@ private: static S32 sTopPad; static LLUIImagePtr sFolderArrowImg; static LLUIImagePtr sSelectionImg; + static LLUIImagePtr sFavoriteImg; + static LLUIImagePtr sFavoriteContentImg; static LLFontGL* sSuffixFont; LLFontVertexBuffer mLabelFontBuffer; @@ -400,6 +412,19 @@ public: // Returns true is this object and all of its children can be moved virtual bool isMovable(); + bool isFavorite() const { return mIsFavorite; } + bool hasFavorites() const { return mHasFavorites; } + void setHasFavorites(bool val) { mHasFavorites = val; } + void updateHasFavorites(bool new_childs_value); +private: + static void onIdleUpdateFavorites(void* data); + + constexpr static S32 FAVORITE_ADDED = 1; + constexpr static S32 FAVORITE_REMOVED = 2; + constexpr static S32 FAVORITE_CLEANUP = 4; + S32 mFavoritesDirtyFlags { 0 }; +public: + // destroys this folder, and all children virtual void destroyView(); void destroyRoot(); diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index 9372818ca5..07e8b890b8 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -162,6 +162,7 @@ public: virtual void navigateToFolder(bool new_window = false, bool change_mode = false) = 0; + virtual bool isFavorite() const = 0; virtual bool isItemWearable() const { return false; } virtual bool isItemRenameable() const = 0; @@ -170,7 +171,8 @@ public: virtual bool isItemMovable( void ) const = 0; // Can be moved to another folder virtual void move( LLFolderViewModelItem* parent_listener ) = 0; - virtual bool isItemRemovable( bool check_worn = true ) const = 0; // Can be destroyed + virtual bool isItemRemovable( bool check_worn = true) const = 0; // Can be destroyed + virtual bool isItemInTrash(void) const = 0; virtual bool removeItem() = 0; virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0; @@ -183,6 +185,9 @@ public: virtual void pasteFromClipboard() = 0; virtual void pasteLinkFromClipboard() = 0; + virtual bool isAgentInventory() const = 0; + virtual bool isAgentInventoryRoot() const = 0; + virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; virtual bool potentiallyVisible() = 0; // is the item definitely visible or we haven't made up our minds yet? @@ -219,6 +224,7 @@ public: virtual S32 getSortVersion() = 0; virtual void setSortVersion(S32 version) = 0; virtual void setParent(LLFolderViewModelItem* parent) = 0; + virtual const LLFolderViewModelItem* getParent() = 0; virtual bool hasParent() = 0; protected: @@ -249,14 +255,14 @@ public: mChildren.clear(); } - void requestSort() { mSortVersion = -1; } - S32 getSortVersion() { return mSortVersion; } - void setSortVersion(S32 version) { mSortVersion = version;} + void requestSort() override { mSortVersion = -1; } + S32 getSortVersion() override { return mSortVersion; } + void setSortVersion(S32 version) override { mSortVersion = version;} - S32 getLastFilterGeneration() const { return mLastFilterGeneration; } + S32 getLastFilterGeneration() const override { return mLastFilterGeneration; } S32 getLastFolderFilterGeneration() const { return mLastFolderFilterGeneration; } - S32 getMarkedDirtyGeneration() const { return mMarkedDirtyGeneration; } - void dirtyFilter() + S32 getMarkedDirtyGeneration() const override { return mMarkedDirtyGeneration; } + void dirtyFilter() override { if(mMarkedDirtyGeneration < 0) { @@ -271,7 +277,7 @@ public: mParent->dirtyFilter(); } } - void dirtyDescendantsFilter() + void dirtyDescendantsFilter() override { mMostFilteredDescendantGeneration = -1; if (mParent) @@ -279,13 +285,13 @@ public: mParent->dirtyDescendantsFilter(); } } - bool hasFilterStringMatch(); - std::string::size_type getFilterStringOffset(); - std::string::size_type getFilterStringSize(); + bool hasFilterStringMatch() override; + std::string::size_type getFilterStringOffset() override; + std::string::size_type getFilterStringSize() override; - typedef std::list<LLFolderViewModelItem*> child_list_t; + typedef std::list<LLPointer<LLFolderViewModelItem> > child_list_t; - virtual void addChild(LLFolderViewModelItem* child) + virtual void addChild(LLFolderViewModelItem* child) override { mChildren.push_back(child); child->setParent(this); @@ -293,15 +299,15 @@ public: requestSort(); } - virtual void removeChild(LLFolderViewModelItem* child) + virtual void removeChild(LLFolderViewModelItem* child) override final { - mChildren.remove(child); child->setParent(NULL); + mChildren.remove(child); dirtyDescendantsFilter(); dirtyFilter(); } - virtual void clearChildren() + virtual void clearChildren() override { // We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); }); @@ -314,7 +320,7 @@ public: child_list_t::const_iterator getChildrenEnd() const { return mChildren.end(); } child_list_t::size_type getChildrenCount() const { return mChildren.size(); } - void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) + void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) override { mPassedFilter = passed; mLastFilterGeneration = filter_generation; @@ -323,20 +329,20 @@ public: mMarkedDirtyGeneration = -1; } - void setPassedFolderFilter(bool passed, S32 filter_generation) + void setPassedFolderFilter(bool passed, S32 filter_generation) override { mPassedFolderFilter = passed; mLastFolderFilterGeneration = filter_generation; } - virtual bool potentiallyVisible() + virtual bool potentiallyVisible() override { return passedFilter() // we've passed the filter || (getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration()) // or we don't know yet || descendantsPassedFilter(); } - virtual bool passedFilter(S32 filter_generation = -1) + virtual bool passedFilter(S32 filter_generation = -1) override { if (filter_generation < 0) { @@ -347,7 +353,7 @@ public: return passed_folder_filter && (passed_filter || descendantsPassedFilter(filter_generation)); } - virtual bool descendantsPassedFilter(S32 filter_generation = -1) + virtual bool descendantsPassedFilter(S32 filter_generation = -1) override { if (filter_generation < 0) { @@ -356,10 +362,10 @@ public: return mMostFilteredDescendantGeneration >= filter_generation; } - protected: - virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; } - virtual bool hasParent() { return mParent != NULL; } + virtual void setParent(LLFolderViewModelItem* parent) override final { mParent = parent; } + virtual const LLFolderViewModelItem* getParent() override { return mParent; }; + virtual bool hasParent() override { return mParent != NULL; } S32 mSortVersion; bool mPassedFilter; @@ -376,7 +382,7 @@ protected: LLFolderViewModelItem* mParent; LLFolderViewModelInterface& mRootViewModel; - void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;} + void setFolderViewItem(LLFolderViewItem* folder_view_item) override { mFolderViewItem = folder_view_item;} LLFolderViewItem* mFolderViewItem; }; @@ -390,15 +396,15 @@ public: mFolderView(NULL) {} - virtual void requestSortAll() + virtual void requestSortAll() override { // sort everything mTargetSortVersion++; } - virtual std::string getStatusText(bool is_empty_folder = false); - virtual void filter(); + virtual std::string getStatusText(bool is_empty_folder = false) override; + virtual void filter() override; - void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;} + void setFolderView(LLFolderView* folder_view) override { mFolderView = folder_view;} protected: bool needsSort(class LLFolderViewModelItem* item); @@ -426,16 +432,16 @@ public: virtual SortType& getSorter() { return *mSorter; } virtual const SortType& getSorter() const { return *mSorter; } - virtual void setSorter(const SortType& sorter) { mSorter.reset(new SortType(sorter)); requestSortAll(); } + virtual void setSorter(const SortType& sorter) { mSorter = std::make_unique<SortType>(sorter); requestSortAll(); } - virtual FilterType& getFilter() { return *mFilter; } - virtual const FilterType& getFilter() const { return *mFilter; } - virtual void setFilter(const FilterType& filter) { mFilter.reset(new FilterType(filter)); } + virtual FilterType& getFilter() override { return *mFilter; } + virtual const FilterType& getFilter() const override { return *mFilter; } + virtual void setFilter(const FilterType& filter) { mFilter = std::make_unique<FilterType>(filter); } // By default, we assume the content is available. If a network fetch mechanism is implemented for the model, // this method needs to be overloaded and return the relevant fetch status. - virtual bool contentsReady() { return true; } - virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; } + virtual bool contentsReady() override { return true; } + virtual bool isFolderComplete(LLFolderViewFolder* folder) override { return true; } struct ViewModelCompare { @@ -456,7 +462,7 @@ public: const SortType& mSorter; }; - void sort(LLFolderViewFolder* folder) + void sort(LLFolderViewFolder* folder) override { if (needsSort(folder->getViewModelItem())) { diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h index da5570d922..953963b683 100644 --- a/indra/llui/llfunctorregistry.h +++ b/indra/llui/llfunctorregistry.h @@ -31,8 +31,6 @@ #include <string> #include <map> -#include <boost/function.hpp> - #include "llsd.h" #include "llsingleton.h" diff --git a/indra/llui/lllazyvalue.h b/indra/llui/lllazyvalue.h index 622e69ce95..fc15ead032 100644 --- a/indra/llui/lllazyvalue.h +++ b/indra/llui/lllazyvalue.h @@ -28,15 +28,16 @@ #ifndef LL_LAZY_VALUE_H #define LL_LAZY_VALUE_H -#include <boost/function.hpp> +#include <functional> +#include <type_traits> // Holds on to a value of type T *or* calls a functor to generate a value of type T template<typename T> class LLLazyValue { public: - typedef typename boost::add_reference<typename boost::add_const<T>::type>::type T_const_ref; - typedef typename boost::function<T_const_ref (void)> function_type; + typedef typename std::add_lvalue_reference<typename std::add_const<T>::type>::type T_const_ref; + typedef typename std::function<T_const_ref (void)> function_type; public: LLLazyValue(const function_type& value) diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 45dab88e87..b534c8d4e8 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -2230,6 +2230,9 @@ void LLLineEditor::clear() { mText.clear(); setCursor(0); + mFontBufferPreSelection.reset(); + mFontBufferSelection.reset(); + mFontBufferPostSelection.reset(); } //virtual diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 7533f76f1d..3f762822ee 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -60,7 +60,7 @@ class LLLineEditor { public: - typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t; + typedef std::function<void (LLLineEditor* caller)> keystroke_callback_t; struct MaxLength : public LLInitParam::ChoiceBlock<MaxLength> { @@ -259,7 +259,7 @@ public: void setSelectAllonCommit(bool b) { mSelectAllonCommit = b; } void onKeystroke(); - typedef boost::function<void (LLLineEditor* caller, void* user_data)> callback_t; + typedef std::function<void (LLLineEditor* caller, void* user_data)> callback_t; void setKeystrokeCallback(callback_t callback, void* user_data); void setMaxTextLength(S32 max_text_length); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index c11b42a348..6ba31c251e 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -46,6 +46,7 @@ #include "llfocusmgr.h" #include "llcoord.h" #include "llwindow.h" +#include "llemojihelper.h" #include "llcriticaldamp.h" #include "lluictrlfactory.h" @@ -1411,6 +1412,7 @@ void LLMenuItemBranchDownGL::openMenu( void ) } else { + LLEmojiHelper::instance().hideHelper(nullptr, true); if (branch->getTornOff()) { LLFloater * branch_parent = dynamic_cast<LLFloater *>(branch->getParent()); @@ -4402,3 +4404,17 @@ bool LLContextMenu::addChild(LLView* view, S32 tab_group) return addContextChild(view, tab_group); } +void LLContextMenu::deleteAllChildren() +{ + mHoverItem = nullptr; + LLMenuGL::deleteAllChildren(); +} + +void LLContextMenu::removeChild(LLView* ctrl) +{ + if (ctrl == mHoverItem) + { + mHoverItem = nullptr; + } + LLMenuGL::removeChild(ctrl); +} diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index ff9456acc6..bca0a731fc 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -37,7 +37,8 @@ #include "llfloater.h" #include "lluistring.h" #include "llview.h" -#include <boost/function.hpp> + +#include <boost/bind.hpp> extern S32 MENU_BAR_HEIGHT; extern S32 MENU_BAR_WIDTH; @@ -729,6 +730,8 @@ public: virtual bool handleRightMouseUp ( S32 x, S32 y, MASK mask ); virtual bool addChild (LLView* view, S32 tab_group = 0); + /*virtual*/ void deleteAllChildren(); + /*virtual*/ void removeChild(LLView* ctrl); LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); } diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp index c5c31f7252..225ff607ad 100644 --- a/indra/llui/llmodaldialog.cpp +++ b/indra/llui/llmodaldialog.cpp @@ -28,6 +28,7 @@ #include "llmodaldialog.h" +#include "llemojihelper.h" #include "llfocusmgr.h" #include "v4color.h" #include "v2math.h" @@ -35,6 +36,7 @@ #include "llwindow.h" #include "llkeyboard.h" #include "llmenugl.h" + // static std::list<LLModalDialog*> LLModalDialog::sModalStack; @@ -98,7 +100,7 @@ void LLModalDialog::onOpen(const LLSD& key) { if (mModal) { - // If Modal, Hide the active modal dialog + // If Modal, hide the active modal dialog if (!sModalStack.empty()) { LLModalDialog* front = sModalStack.front(); @@ -155,6 +157,12 @@ void LLModalDialog::setVisible( bool visible ) { if( visible ) { + // Hide all menus currently shown + LLMenuGL::sMenuContainer->hideMenus(); + + // Hide EmojiPicker if it is shown + LLEmojiHelper::instance().hideHelper(nullptr, true); + // This is a modal dialog. It sucks up all mouse and keyboard operations. gFocusMgr.setMouseCapture( this ); @@ -301,7 +309,6 @@ void LLModalDialog::centerOnScreen() centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY]))); } - // static void LLModalDialog::onAppFocusLost() { @@ -333,6 +340,7 @@ void LLModalDialog::onAppFocusGained() } } +// static void LLModalDialog::shutdownModals() { // This method is only for use during app shutdown. ~LLModalDialog() diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index a05feab1d9..0ffe6cff5e 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -457,7 +457,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par mTags.push_back(tag.value); } - mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form)); + mForm = std::make_shared<LLNotificationForm>(p.name, p.form_ref.form); } LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationVisibilityRule::Rule &p) @@ -875,7 +875,7 @@ void LLNotification::init(const std::string& template_name, const LLSD& form_ele // TODO: something like this so that a missing alert is sensible: //mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions); - mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm)); + mForm = std::make_shared<LLNotificationForm>(*mTemplatep->mForm); mForm->append(form_elements); // apply substitution to form labels @@ -1249,7 +1249,7 @@ LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything), mIgnoreAllNotifications(false) { - mListener.reset(new LLNotificationsListener(*this)); + mListener = std::make_unique<LLNotificationsListener>(*this); LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2)); // touch the instance tracker for notification channels, so that it will still be around in our destructor @@ -1487,7 +1487,7 @@ bool LLNotifications::templateExists(std::string_view name) void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option) { - LLNotificationPtr temp_notify(new LLNotification(params)); + LLNotificationPtr temp_notify = std::make_shared<LLNotification>(params); if (!temp_notify->getForm()) { @@ -1653,7 +1653,7 @@ bool LLNotifications::loadTemplates() replaceFormText(notification.form_ref.form, "$ignoretext", notification.form_ref.form_template.ignore_text); } } - mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification)); + mTemplates[notification.name] = std::make_shared<LLNotificationTemplate>(notification); } LL_INFOS("Notifications") << "...done" << LL_ENDL; @@ -1683,7 +1683,7 @@ bool LLNotifications::loadVisibilityRules() for (const LLNotificationVisibilityRule::Rule& rule : params.rules) { - mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(rule))); + mVisibilityRules.push_back(std::make_shared<LLNotificationVisibilityRule>(rule)); } return true; @@ -1726,7 +1726,7 @@ LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& subs // generalized add function that takes a parameter block object for more complex instantiations LLNotificationPtr LLNotifications::add(const LLNotification::Params& p) { - LLNotificationPtr pNotif(new LLNotification(p)); + LLNotificationPtr pNotif = std::make_shared<LLNotification>(p); add(pNotif); return pNotif; } @@ -1834,7 +1834,7 @@ void LLNotifications::update(const LLNotificationPtr pNotif) LLNotificationPtr LLNotifications::find(LLUUID uuid) { - LLNotificationPtr target = LLNotificationPtr(new LLNotification(LLNotification::Params().id(uuid))); + LLNotificationPtr target = std::make_shared<LLNotification>(LLNotification::Params().id(uuid)); LLNotificationSet::iterator it=mItems.find(target); if (it == mItems.end()) { diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 3c8e1e85fa..d56c459560 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -75,6 +75,7 @@ * */ +#include <functional> #include <string> #include <list> #include <vector> @@ -83,8 +84,6 @@ #include <iomanip> #include <sstream> -#include <boost/utility.hpp> -#include <boost/type_traits.hpp> #include <boost/signals2.hpp> #include <boost/range.hpp> #include <boost/intrusive_ptr.hpp> @@ -129,7 +128,7 @@ public: virtual void fromLLSD(const LLSD& params) = 0; }; -typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder; +typedef std::function<void (const LLSD&, const LLSD&)> LLNotificationResponder; typedef std::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr; @@ -303,7 +302,6 @@ typedef std::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRu * shared pointer. */ class LLNotification : - boost::noncopyable, public std::enable_shared_from_this<LLNotification> { LOG_CLASS(LLNotification); @@ -429,6 +427,10 @@ private: public: LLNotification(const LLSDParamAdapter<Params>& p); + // Non-copyable + LLNotification(const LLNotification&) = delete; + LLNotification& operator=(const LLNotification&) = delete; + void setResponseFunctor(std::string const &responseFunctorName); void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb); @@ -666,8 +668,8 @@ namespace LLNotificationFilters template<typename T> struct filterBy { - typedef boost::function<T (LLNotificationPtr)> field_t; - typedef typename boost::remove_reference<T>::type value_t; + typedef std::function<T (LLNotificationPtr)> field_t; + typedef typename std::remove_reference<T>::type value_t; filterBy(field_t field, value_t value, EComparison comparison = EQUAL) : mField(field), @@ -712,7 +714,7 @@ namespace LLNotificationComparators }; }; -typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter; +typedef std::function<bool (LLNotificationPtr)> LLNotificationFilter; typedef std::set<LLNotificationPtr, LLNotificationComparators::orderByUUID> LLNotificationSet; typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap; @@ -817,10 +819,9 @@ typedef boost::intrusive_ptr<LLNotificationChannel> LLNotificationChannelPtr; // manages a list of notifications // Note that if this is ever copied around, we might find ourselves with multiple copies // of a queue with notifications being added to different nonequivalent copies. So we -// make it inherit from boost::noncopyable, and then create a map of LLPointer to manage it. +// delete the copy operator and constructor, and then create a map of LLPointer to manage it. // class LLNotificationChannel : - boost::noncopyable, public LLNotificationChannelBase, public LLInstanceTracker<LLNotificationChannel, std::string> { @@ -843,6 +844,10 @@ public: virtual ~LLNotificationChannel(); typedef LLNotificationSet::iterator Iterator; + // Non-copyable + LLNotificationChannel(const LLNotificationChannel&) = delete; + LLNotificationChannel& operator=(const LLNotificationChannel&) = delete; + std::string getName() const { return mName; } typedef std::vector<std::string>::const_iterator parents_iter; boost::iterator_range<parents_iter> getParents() const @@ -854,7 +859,7 @@ public: S32 size() const; size_t size(); - typedef boost::function<void(LLNotificationPtr)> NotificationProcess; + typedef std::function<void(LLNotificationPtr)> NotificationProcess; void forEachNotification(NotificationProcess process); std::string summarize(); diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp index 9c1fc27c51..d07d42bdba 100644 --- a/indra/llui/llnotificationslistener.cpp +++ b/indra/llui/llnotificationslistener.cpp @@ -266,7 +266,7 @@ void LLNotificationsListener::forward(const LLSD& params) entry(mForwarders.insert(ForwarderMap::value_type(channel, ForwarderMap::mapped_type())).first); if (! entry->second) { - entry->second.reset(new Forwarder(mNotifications, channel)); + entry->second = std::make_shared<Forwarder>(mNotifications, channel); } // Now, whether this Forwarder is brand-new or not, update it with the new // request info. diff --git a/indra/llui/llnotificationsutil.cpp b/indra/llui/llnotificationsutil.cpp index c1cad431c5..6b570d043f 100644 --- a/indra/llui/llnotificationsutil.cpp +++ b/indra/llui/llnotificationsutil.cpp @@ -71,7 +71,7 @@ LLNotificationPtr LLNotificationsUtil::add(const std::string& name, LLNotificationPtr LLNotificationsUtil::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, - boost::function<void (const LLSD&, const LLSD&)> functor) + std::function<void (const LLSD&, const LLSD&)> functor) { LLNotification::Params::Functor functor_p; functor_p.function = functor; diff --git a/indra/llui/llnotificationsutil.h b/indra/llui/llnotificationsutil.h index f21d93a50e..73e64e47ba 100644 --- a/indra/llui/llnotificationsutil.h +++ b/indra/llui/llnotificationsutil.h @@ -32,7 +32,7 @@ #include "llnotificationptr.h" #include "lluuid.h" -#include <boost/function.hpp> +#include <functional> class LLSD; @@ -55,7 +55,7 @@ namespace LLNotificationsUtil LLNotificationPtr add(const std::string& name, const LLSD& substitutions, const LLSD& payload, - boost::function<void (const LLSD&, const LLSD&)> functor); + std::function<void (const LLSD&, const LLSD&)> functor); S32 getSelectedOption(const LLSD& notification, const LLSD& response); diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index db314cae0f..2100b23783 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -662,12 +662,12 @@ bool LLPanel::childHasFocus(std::string_view id) // Prefer getChild<LLUICtrl>("foo")->setCommitCallback(boost:bind(...)), // which takes a generic slot. Or use mCommitCallbackRegistrar.add() with // a named callback and reference it in XML. -void LLPanel::childSetCommitCallback(std::string_view id, boost::function<void (LLUICtrl*,void*)> cb, void* data) +void LLPanel::childSetCommitCallback(std::string_view id, std::function<void (LLUICtrl*,void*)> cb, void* data) { LLUICtrl* child = findChild<LLUICtrl>(id); if (child) { - child->setCommitCallback(boost::bind(cb, child, data)); + child->setCommitCallback(std::bind(cb, child, data)); } } @@ -759,12 +759,12 @@ void LLPanel::childSetAction(std::string_view id, const commit_signal_t::slot_ty } } -void LLPanel::childSetAction(std::string_view id, boost::function<void(void*)> function, void* value) +void LLPanel::childSetAction(std::string_view id, std::function<void(void*)> function, void* value) { LLButton* button = findChild<LLButton>(id); if (button) { - button->setClickedCallback(boost::bind(function, value)); + button->setClickedCallback(std::bind(function, value)); } } diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index f085c123c1..fe861dc719 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -191,7 +191,7 @@ public: // Prefer getChild<LLUICtrl>("foo")->setCommitCallback(boost:bind(...)), // which takes a generic slot. Or use mCommitCallbackRegistrar.add() with // a named callback and reference it in XML. - void childSetCommitCallback(std::string_view id, boost::function<void (LLUICtrl*,void*)> cb, void* data); + void childSetCommitCallback(std::string_view id, std::function<void (LLUICtrl*,void*)> cb, void* data); void childSetColor(std::string_view id, const LLUIColor& color); LLCtrlSelectionInterface* childGetSelectionInterface(std::string_view id) const; @@ -208,7 +208,7 @@ public: bool childSetLabelArg(std::string_view id, const std::string& key, const LLStringExplicit& text); // LLButton - void childSetAction(std::string_view id, boost::function<void(void*)> function, void* value); + void childSetAction(std::string_view id, std::function<void(void*)> function, void* value); void childSetAction(std::string_view id, const commit_signal_t::slot_type& function); static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); @@ -262,7 +262,7 @@ extern template class LLPanel* LLView::getChild<class LLPanel>( std::string_view name, bool recurse) const; #endif -typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc; +typedef std::function<LLPanel* (void)> LLPanelClassCreatorFunc; // local static instance for registering a particular panel class diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h index 68bf0fd95e..d95536c360 100644 --- a/indra/llui/llresizebar.h +++ b/indra/llui/llresizebar.h @@ -62,7 +62,7 @@ public: void setEnableSnapping(bool enable) { mSnappingEnabled = enable; } void setAllowDoubleClickSnapping(bool allow) { mAllowDoubleClickSnapping = allow; } bool canResize() const { return getEnabled() && mMaxSize > mMinSize; } - void setResizeListener(boost::function<void(void*)> listener) {mResizeListener = listener;} + void setResizeListener(std::function<void(void*)> listener) { mResizeListener = listener; } void setImagePanel(LLPanel * panelp); LLPanel * getImagePanel() const; @@ -78,7 +78,7 @@ private: bool mSnappingEnabled, mAllowDoubleClickSnapping; LLView* mResizingView; - boost::function<void(void*)> mResizeListener; + std::function<void(void*)> mResizeListener; LLPointer<LLUIImage> mDragHandleImage; LLPanel * mImagePanel; }; diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index 9607355a9d..c49d2b534a 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -40,7 +40,7 @@ class LLScrollbar { public: - typedef boost::function<void (S32, LLScrollbar*)> callback_t; + typedef std::function<void (S32, LLScrollbar*)> callback_t; struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index a3108d77e8..bdf88768c3 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -98,6 +98,7 @@ const LLSD LLScrollListCell::getAltValue() const LLScrollListIcon::LLScrollListIcon(const LLScrollListCell::Params& p) : LLScrollListCell(p), mIcon(LLUI::getUIImage(p.value().asString())), + mIconSize(0), mColor(p.color), mAlignment(p.font_halign) {} @@ -140,20 +141,32 @@ void LLScrollListIcon::setValue(const LLSD& value) } } - void LLScrollListIcon::setColor(const LLColor4& color) { mColor = color; } +void LLScrollListIcon::setIconSize(S32 size) +{ + mIconSize = size; +} + S32 LLScrollListIcon::getWidth() const { // if no specified fix width, use width of icon - if (LLScrollListCell::getWidth() == 0 && mIcon.notNull()) + if (LLScrollListCell::getWidth() != 0) + { + return LLScrollListCell::getWidth(); + } + if (mIconSize != 0) + { + return mIconSize; + } + if (mIcon.notNull()) { return mIcon->getWidth(); } - return LLScrollListCell::getWidth(); + return 0; } @@ -161,16 +174,23 @@ void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_col { if (mIcon) { + S32 draw_width = mIcon->getWidth(); + S32 draw_height = mIcon->getHeight(); + if (mIconSize != 0) + { + draw_width = mIconSize; + draw_height = mIconSize; + } // else will draw full icon even if cell is smaller switch(mAlignment) { case LLFontGL::LEFT: - mIcon->draw(0, 0, mColor); + mIcon->draw(0, 0, draw_width, draw_height, mColor); break; case LLFontGL::RIGHT: - mIcon->draw(getWidth() - mIcon->getWidth(), 0, mColor); + mIcon->draw(getWidth() - draw_width, 0, draw_width, draw_height, mColor); break; case LLFontGL::HCENTER: - mIcon->draw((getWidth() - mIcon->getWidth()) / 2, 0, mColor); + mIcon->draw((getWidth() - draw_width) / 2, 0, draw_width, draw_height, mColor); break; default: break; diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index 7dded3c0b7..f0a0f216b4 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -197,11 +197,13 @@ public: /*virtual*/ const LLSD getValue() const; /*virtual*/ void setColor(const LLColor4&); /*virtual*/ void setValue(const LLSD& value); + void setIconSize(S32 size); private: LLPointer<LLUIImage> mIcon; LLColor4 mColor; LLFontGL::HAlign mAlignment; + S32 mIconSize; }; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 245339b107..b459c67dad 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -190,19 +190,19 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mColumnsDirty(false), mMaxItemCount(INT_MAX), mBorderThickness( 2 ), - mOnDoubleClickCallback( NULL ), - mOnMaximumSelectCallback( NULL ), - mOnSortChangedCallback( NULL ), + mOnDoubleClickCallback(nullptr), + mOnMaximumSelectCallback(nullptr), + mOnSortChangedCallback(nullptr), mHighlightedItem(-1), - mBorder(NULL), - mSortCallback(NULL), + mBorder(nullptr), + mSortCallback(nullptr), mNumDynamicWidthColumns(0), mTotalStaticColumnWidth(0), mTotalColumnPadding(0), mSorted(false), mDirty(false), mOriginalSelection(-1), - mLastSelected(NULL), + mLastSelected(nullptr), mHeadingHeight(p.heading_height), mAllowMultipleSelection(p.multi_select), mDisplayColumnHeaders(p.draw_heading), @@ -222,7 +222,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mRowPadding(p.row_padding), mAlternateSort(false), mContextMenuType(MENU_NONE), - mIsFriendSignal(NULL) + mIsFriendSignal(nullptr) { mItemListRect.setOriginAndSize( mBorderThickness, @@ -1007,7 +1007,7 @@ void LLScrollListCtrl::deleteItems(const LLSD& sd) void LLScrollListCtrl::deleteSelectedItems() { item_list::iterator iter; - for (iter = mItemList.begin(); iter < mItemList.end(); ) + for (iter = mItemList.begin(); iter != mItemList.end(); ) { LLScrollListItem* itemp = *iter; if (itemp->getSelected()) diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 1f04100306..d3735c5052 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -77,7 +77,7 @@ public: }; // *TODO: Add callbacks to Params - typedef boost::function<void (void)> callback_t; + typedef std::function<void (void)> callback_t; template<typename T> struct maximum { @@ -241,7 +241,7 @@ public: void setMaximumSelectCallback( callback_t cb) { mOnMaximumSelectCallback = cb; } void setSortChangedCallback( callback_t cb) { mOnSortChangedCallback = cb; } // Convenience function; *TODO: replace with setter above + boost::bind() in calling code - void setDoubleClickCallback( boost::function<void (void* userdata)> cb, void* userdata) { mOnDoubleClickCallback = boost::bind(cb, userdata); } + void setDoubleClickCallback( std::function<void (void* userdata)> cb, void* userdata) { mOnDoubleClickCallback = std::bind(cb, userdata); } void swapWithNext(S32 index); void swapWithPrevious(S32 index); diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index a0c1e9d0c0..244faf8fe9 100644 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -106,12 +106,12 @@ LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p) LLSearchEditor::~LLSearchEditor() { - mKeystrokeCallback = NULL; - mTextChangedCallback = NULL; + mKeystrokeCallback = nullptr; + mTextChangedCallback = nullptr; setCommitOnFocusLost(false); - mSearchButton = NULL; - mClearButton = NULL; + mSearchButton = nullptr; + mClearButton = nullptr; mSearchEditor->deleteAllChildren(); deleteAllChildren(); } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 778b253c3c..2079ff17fc 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -185,6 +185,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mURLClickSignal(NULL), mIsFriendSignal(NULL), mIsObjectBlockedSignal(NULL), + mIsObjectReachableSignal(NULL), mMaxTextByteLength( p.max_text_length ), mFont(p.font), mFontShadow(p.font_shadow), @@ -290,6 +291,7 @@ LLTextBase::~LLTextBase() delete mURLClickSignal; delete mIsFriendSignal; delete mIsObjectBlockedSignal; + delete mIsObjectReachableSignal; } void LLTextBase::initFromParams(const LLTextBase::Params& p) @@ -1036,8 +1038,37 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s { LLStyleSP emoji_style; LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL; + LLTextSegment* segmentp = nullptr; + segment_vec_t::iterator seg_iter; + if (segments && segments->size() > 0) + { + seg_iter = segments->begin(); + segmentp = *seg_iter; + } for (S32 text_kitty = 0, text_len = static_cast<S32>(wstr.size()); text_kitty < text_len; text_kitty++) { + if (segmentp) + { + if (segmentp->getEnd() <= pos + text_kitty) + { + seg_iter++; + if (seg_iter != segments->end()) + { + segmentp = *seg_iter; + } + else + { + segmentp = nullptr; + } + } + if (segmentp && !segmentp->getPermitsEmoji()) + { + // Some segments, like LLInlineViewSegment do not permit splitting + // and should not be interrupted by emoji segments + continue; + } + } + llwchar code = wstr[text_kitty]; bool isEmoji = ed ? ed->isEmoji(code) : LLStringOps::isEmoji(code); if (isEmoji) @@ -1069,6 +1100,14 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) { + S32 text_length = (S32)getLength(); + if (pos >= text_length || pos < 0) + { + return 0; // nothing to remove + } + // Clamp length to not go past the end of the text + length = std::min(length, text_length - pos); + beforeValueChange(); segment_set_t::iterator seg_iter = getSegIterContaining(pos); while(seg_iter != mSegments.end()) @@ -1438,6 +1477,8 @@ void LLTextBase::reshape(S32 width, S32 height, bool called_from_parent) // up-to-date mVisibleTextRect updateRects(); + // Todo: This might be wrong. updateRects already sets needsReflow conditionaly. + // Reflow is expensive and doing it at any twith can be too much. needsReflow(); } } @@ -2227,7 +2268,9 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) registrar.add("Url.RemoveFriend", boost::bind(&LLUrlAction::removeFriend, url)); registrar.add("Url.ReportAbuse", boost::bind(&LLUrlAction::reportAbuse, url)); registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url)); + registrar.add("Url.ZoomInObject", boost::bind(&LLUrlAction::zoomInObject, url)); registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url)); + registrar.add("Url.ShowParcelOnMap", boost::bind(&LLUrlAction::showParcelOnMap, url)); registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); @@ -2271,6 +2314,15 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) unblockButton->setVisible(is_blocked); } } + + if (mIsObjectReachableSignal) + { + bool is_reachable = *(*mIsObjectReachableSignal)(LLUUID(LLUrlAction::getObjectId(url))); + if (LLView* zoom_btn = menu->getChild<LLView>("zoom_in")) + { + zoom_btn->setEnabled(is_reachable); + } + } menu->show(x, y); LLMenuGL::showPopup(this, menu, x, y); } @@ -3377,6 +3429,15 @@ boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_bloc return mIsObjectBlockedSignal->connect(cb); } +boost::signals2::connection LLTextBase::setIsObjectReachableCallback(const is_obj_reachable_signal_t::slot_type& cb) +{ + if (!mIsObjectReachableSignal) + { + mIsObjectReachableSignal = new is_obj_reachable_signal_t(); + } + return mIsObjectReachableSignal->connect(cb); +} + // // LLTextSegment // @@ -3459,6 +3520,11 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e { mFontHeight = mStyle->getFont()->getLineHeight(); mCanEdit = !mStyle->getDrawHighlightBg(); + if (!mCanEdit) + { + // Emoji shouldn't split the segment with the mention. + mPermitsEmoji = false; + } LLUIImagePtr image = mStyle->getImage(); if (image.notNull()) @@ -3755,7 +3821,7 @@ bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& w { height = 0; width = 0; - if (num_chars > 0) + if (num_chars > 0 && (mStart + first_char >= 0)) { height = mFontHeight; const LLWString &text = getWText(); @@ -3979,6 +4045,7 @@ LLInlineViewSegment::LLInlineViewSegment(const Params& p, S32 start, S32 end) mTopPad(p.top_pad), mBottomPad(p.bottom_pad) { + mPermitsEmoji = false; } LLInlineViewSegment::~LLInlineViewSegment() diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 8ca653acb9..3ab5e905e3 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -61,13 +61,15 @@ class LLTextSegment public: LLTextSegment(S32 start, S32 end) : mStart(start), - mEnd(end) + mEnd(end), + mPermitsEmoji(true) {} 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; + bool getPermitsEmoji() const { return mPermitsEmoji; }; 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; @@ -125,6 +127,8 @@ public: protected: S32 mStart; S32 mEnd; + + bool mPermitsEmoji; }; class LLNormalTextSegment : public LLTextSegment @@ -255,6 +259,7 @@ public: /*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 false; } + /*virtual*/ bool getPermitsEmoji() const { return false; } /*virtual*/ void unlinkFromDocument(class LLTextBase* editor); /*virtual*/ void linkToDocument(class LLTextBase* editor); @@ -325,6 +330,7 @@ public: typedef boost::signals2::signal<bool (const LLUUID& user_id)> is_friend_signal_t; typedef boost::signals2::signal<bool (const LLUUID& blocked_id, const std::string from)> is_blocked_signal_t; + typedef boost::signals2::signal<bool (const LLUUID& obj_id)> is_obj_reachable_signal_t; struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams> { @@ -535,6 +541,7 @@ public: boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb); boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb); boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb); + boost::signals2::connection setIsObjectReachableCallback(const is_obj_reachable_signal_t::slot_type& cb); void setWordWrap(bool wrap); LLScrollContainer* getScrollContainer() const { return mScroller; } @@ -783,6 +790,7 @@ protected: // Used to check if user with given ID is avatar's friend is_friend_signal_t* mIsFriendSignal; is_blocked_signal_t* mIsObjectBlockedSignal; + is_obj_reachable_signal_t* mIsObjectReachableSignal; LLUIString mLabel; // text label that is visible when no user text provided }; diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 9f945d3735..d2a21998a6 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -43,7 +43,7 @@ template class LLTextBox* LLView::getChild<class LLTextBox>( LLTextBox::LLTextBox(const LLTextBox::Params& p) : LLTextBase(p), - mClickedCallback(NULL), + mClickedCallback(nullptr), mShowCursorHand(true) { mSkipTripleClick = true; @@ -135,9 +135,9 @@ void LLTextBox::setText(const LLStringExplicit& text , const LLStyle::Params& in LLTextBase::setText(mText.getString(), input_params ); } -void LLTextBox::setClickedCallback( boost::function<void (void*)> cb, void* userdata /*= NULL */ ) +void LLTextBox::setClickedCallback(std::function<void (void*)> cb, void* userdata /*= nullptr */) { - mClickedCallback = boost::bind(cb, userdata); + mClickedCallback = std::bind(cb, userdata); } S32 LLTextBox::getTextPixelWidth() diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index 507d8f3ee6..8716917ced 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -36,7 +36,7 @@ class LLTextBox : public: // *TODO: Add callback to Params - typedef boost::function<void (void)> callback_t; + typedef std::function<void (void)> callback_t; struct Params : public LLInitParam::Block<Params, LLTextBase::Params> {}; @@ -58,7 +58,7 @@ public: void setRightAlign() { mHAlign = LLFontGL::RIGHT; } void setHAlign(LLFontGL::HAlign align) { mHAlign = align; } - void setClickedCallback(boost::function<void(void*)> cb, void* userdata = NULL); + void setClickedCallback(std::function<void(void*)> cb, void* userdata = nullptr); void reshapeToFitText(bool called_from_parent = false); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index cfe729be06..fcdf3782ae 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -274,7 +274,9 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mShowChatMentionPicker(false), mEnableTooltipPaste(p.enable_tooltip_paste), mPassDelete(false), - mKeepSelectionOnReturn(false) + mKeepSelectionOnReturn(false), + mSelectAllOnFocusReceived(false), + mSelectedOnFocusReceived(false) { mSourceID.generate(); @@ -398,6 +400,7 @@ void LLTextEditor::selectNext(const std::string& search_text_in, bool case_insen setCursorPos(loc); mIsSelecting = true; + mSelectedOnFocusReceived = false; mSelectionEnd = mCursorPos; mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); } @@ -677,6 +680,13 @@ bool LLTextEditor::canSelectAll() const return true; } +//virtual +void LLTextEditor::deselect() +{ + LLTextBase::deselect(); + mSelectedOnFocusReceived = false; +} + // virtual void LLTextEditor::selectAll() { @@ -694,6 +704,11 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p endSelection(); } +void LLTextEditor::setSelectAllOnFocusReceived(bool b) +{ + mSelectAllOnFocusReceived = b; +} + void LLTextEditor::insertEmoji(llwchar emoji) { LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; @@ -795,8 +810,16 @@ bool LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) // Delay cursor flashing resetCursorBlink(); + mSelectedOnFocusReceived = false; if (handled && !gFocusMgr.getMouseCapture()) { + if (!mask && mSelectAllOnFocusReceived) + { + mIsSelecting = false; + mSelectionStart = getLength(); + mSelectionEnd = 0; + mSelectedOnFocusReceived = true; + } gFocusMgr.setMouseCapture( this ); } return handled; @@ -1219,7 +1242,7 @@ void LLTextEditor::addChar(llwchar wc) tryToShowEmojiHelper(); tryToShowMentionHelper(); - if (!mReadOnly && mAutoreplaceCallback != NULL) + if (!mReadOnly && mAutoreplaceCallback != nullptr) { // autoreplace the text, if necessary S32 replacement_start; @@ -2200,6 +2223,11 @@ void LLTextEditor::focusLostHelper() gEditMenuHandler = NULL; } + if (mSelectedOnFocusReceived) + { + deselect(); + } + if (mCommitOnFocusLost) { onCommit(); diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 882bb145df..d9742db34d 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -144,8 +144,10 @@ public: virtual bool canDoDelete() const; virtual void selectAll(); virtual bool canSelectAll() const; + virtual void deselect(); void selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos); + void setSelectAllOnFocusReceived(bool b); virtual bool canLoadOrSaveToFile(); @@ -162,7 +164,7 @@ public: bool allowsEmbeddedItems() const { return mAllowEmbeddedItems; } // Autoreplace (formerly part of LLLineEditor) - typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t; + typedef std::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t; autoreplace_callback_t mAutoreplaceCallback; void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } @@ -336,6 +338,8 @@ private: bool mEnableTooltipPaste; bool mPassDelete; bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter + bool mSelectAllOnFocusReceived; + bool mSelectedOnFocusReceived; LLUUID mSourceID; diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp index 8ffce1b8b4..1454de34c7 100644 --- a/indra/llui/lltextutil.cpp +++ b/indra/llui/lltextutil.cpp @@ -30,7 +30,7 @@ #include "lltextbox.h" #include "llurlmatch.h" -boost::function<bool(LLUrlMatch*,LLTextBase*)> LLTextUtil::TextHelpers::iconCallbackCreationFunction = 0; +std::function<bool(LLUrlMatch*, LLTextBase*)> LLTextUtil::TextHelpers::iconCallbackCreationFunction = nullptr; void LLTextUtil::textboxSetHighlightedVal(LLTextBox *txtbox, const LLStyle::Params& normal_style, const std::string& text, const std::string& hl) { diff --git a/indra/llui/lltextutil.h b/indra/llui/lltextutil.h index f3838e59fa..6328ff133f 100644 --- a/indra/llui/lltextutil.h +++ b/indra/llui/lltextutil.h @@ -74,7 +74,7 @@ namespace LLTextUtil //we need this special callback since we need to create LLAvataIconCtrls while parsing //avatar/group url but can't create LLAvataIconCtrl from LLUI public: - static boost::function<bool(LLUrlMatch*,LLTextBase*)> iconCallbackCreationFunction; + static std::function<bool(LLUrlMatch*,LLTextBase*)> iconCallbackCreationFunction; }; diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index a4ff144d82..096c28b448 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -30,7 +30,6 @@ #include "llstring.h" #include "llinitparam.h" -#include <boost/function.hpp> namespace LLTextValidate { diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 5955a28fa3..785dc85448 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -99,8 +99,8 @@ LLToolBar::LLToolBar(const LLToolBar::Params& p) mWrap(p.wrap), mNeedsLayout(false), mModified(false), - mButtonPanel(NULL), - mCenteringStack(NULL), + mButtonPanel(nullptr), + mCenteringStack(nullptr), mPadLeft(p.pad_left), mPadRight(p.pad_right), mPadTop(p.pad_top), @@ -108,17 +108,17 @@ LLToolBar::LLToolBar(const LLToolBar::Params& p) mPadBetween(p.pad_between), mMinGirth(p.min_girth), mPopupMenuHandle(), - mRightMouseTargetButton(NULL), - mStartDragItemCallback(NULL), - mHandleDragItemCallback(NULL), - mHandleDropCallback(NULL), - mButtonAddSignal(NULL), - mButtonEnterSignal(NULL), - mButtonLeaveSignal(NULL), - mButtonRemoveSignal(NULL), + mRightMouseTargetButton(nullptr), + mStartDragItemCallback(nullptr), + mHandleDragItemCallback(nullptr), + mHandleDropCallback(nullptr), + mButtonAddSignal(nullptr), + mButtonEnterSignal(nullptr), + mButtonLeaveSignal(nullptr), + mButtonRemoveSignal(nullptr), mDragAndDropTarget(false), - mCaretIcon(NULL), - mCenterPanel(NULL) + mCaretIcon(nullptr), + mCenterPanel(nullptr) { mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text; mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_ONLY] = p.button_icon; @@ -1054,7 +1054,7 @@ bool LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, // if drop is set, it's time to call the callback to get the operation done if (handled && drop) { - handled = mHandleDropCallback(cargo_data, x, y, this); + handled = mHandleDropCallback(cargo_data, cargo_type, x, y, this); } // We accept only single tool drop on toolbars @@ -1097,12 +1097,12 @@ LLToolBarButton::LLToolBarButton(const Params& p) mWidthRange(p.button_width), mDesiredHeight(p.desired_height), mId(""), - mIsEnabledSignal(NULL), - mIsRunningSignal(NULL), - mIsStartingSignal(NULL), + mIsEnabledSignal(nullptr), + mIsRunningSignal(nullptr), + mIsStartingSignal(nullptr), mIsDragged(false), - mStartDragItemCallback(NULL), - mHandleDragItemCallback(NULL), + mStartDragItemCallback(nullptr), + mHandleDragItemCallback(nullptr), mOriginalImageSelected(p.image_selected), mOriginalImageUnselected(p.image_unselected), mOriginalImagePressed(p.image_pressed), @@ -1256,7 +1256,7 @@ void LLToolBar::LLCenterLayoutPanel::handleReshape(const LLRect& rect, bool by_u { LLLayoutPanel::handleReshape(rect, by_user); - if (!mReshapeCallback.empty()) + if (mReshapeCallback != nullptr) { LLRect r; localRectToOtherView(mButtonPanel->getRect(), &r, gFloaterView); diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h index 5556406fbd..abf44f259a 100644 --- a/indra/llui/lltoolbar.h +++ b/indra/llui/lltoolbar.h @@ -39,9 +39,9 @@ class LLToolBar; class LLToolBarButton; class LLIconCtrl; -typedef boost::function<void (S32 x, S32 y, LLToolBarButton* button)> tool_startdrag_callback_t; -typedef boost::function<bool (S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type)> tool_handledrag_callback_t; -typedef boost::function<bool (void* data, S32 x, S32 y, LLToolBar* toolbar)> tool_handledrop_callback_t; +typedef std::function<void (S32 x, S32 y, LLToolBarButton* button)> tool_startdrag_callback_t; +typedef std::function<bool (S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type)> tool_handledrag_callback_t; +typedef std::function<bool (void* data, EDragAndDropType cargo_type, S32 x, S32 y, LLToolBar* toolbar)> tool_handledrop_callback_t; class LLToolBarButton : public LLButton { @@ -167,7 +167,7 @@ public: class LLCenterLayoutPanel : public LLLayoutPanel { public: - typedef boost::function<void(LLToolBarEnums::EToolBarLocation tb, const LLRect& rect)> reshape_callback_t; + typedef std::function<void(LLToolBarEnums::EToolBarLocation tb, const LLRect& rect)> reshape_callback_t; virtual ~LLCenterLayoutPanel() {} /*virtual*/ void handleReshape(const LLRect& rect, bool by_user); diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h index 760acddd6f..c9d6937c1a 100644 --- a/indra/llui/lltooltip.h +++ b/indra/llui/lltooltip.h @@ -67,8 +67,8 @@ public: struct Params : public LLInitParam::Block<Params, LLPanel::Params> { - typedef boost::function<void(void)> click_callback_t; - typedef boost::function<LLToolTip*(LLToolTip::Params)> create_callback_t; + typedef std::function<void(void)> click_callback_t; + typedef std::function<LLToolTip*(LLToolTip::Params)> create_callback_t; Optional<std::string> message; Multiple<StyledText> styled_message; diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index e36dae3955..179d1dcaff 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -213,13 +213,8 @@ void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& rem void LLUI::setMousePositionScreen(S32 x, S32 y) { -#if defined(LL_DARWIN) - S32 screen_x = ll_round(((F32)x * getScaleFactor().mV[VX]) / LLView::getWindow()->getSystemUISize()); - S32 screen_y = ll_round(((F32)y * getScaleFactor().mV[VY]) / LLView::getWindow()->getSystemUISize()); -#else S32 screen_x = ll_round((F32)x * getScaleFactor().mV[VX]); S32 screen_y = ll_round((F32)y * getScaleFactor().mV[VY]); -#endif LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert()); } @@ -231,6 +226,11 @@ void LLUI::getMousePositionScreen(S32 *x, S32 *y) LLCoordGL cursor_pos_gl(cursor_pos_window.convert()); *x = ll_round((F32)cursor_pos_gl.mX / getScaleFactor().mV[VX]); *y = ll_round((F32)cursor_pos_gl.mY / getScaleFactor().mV[VY]); +#if defined(LL_SDL) + *x = *x * LLView::getWindow()->getSystemUISize(); + *y = *y * LLView::getWindow()->getSystemUISize(); +#endif + } void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y) diff --git a/indra/llui/llui.h b/indra/llui/llui.h index b2dcb6dc88..2ef64baaf6 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -241,9 +241,9 @@ public: // // Methods // - typedef boost::function<void(LLView*)> add_popup_t; - typedef boost::function<void(LLView*)> remove_popup_t; - typedef boost::function<void(void)> clear_popups_t; + typedef std::function<void(LLView*)> add_popup_t; + typedef std::function<void(LLView*)> remove_popup_t; + typedef std::function<void(void)> clear_popups_t; void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& ); diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index cbabb5a933..05461edd82 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -999,15 +999,16 @@ bool LLUICtrl::findHelpTopic(std::string& help_topic_out) } // *TODO: Deprecate; for backwards compatability only: -boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data) +boost::signals2::connection LLUICtrl::setCommitCallback( std::function<void (LLUICtrl*,void*)> cb, void* data) { - return setCommitCallback( boost::bind(cb, _1, data)); + return setCommitCallback( std::bind(cb, std::placeholders::_1, data)); } -boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb ) + +boost::signals2::connection LLUICtrl::setValidateBeforeCommit( std::function<bool (const LLSD& data)> cb ) { if (!mValidateSignal) mValidateSignal = new enable_signal_t(); - return mValidateSignal->connect(boost::bind(cb, _2)); + return mValidateSignal->connect(std::bind(cb, std::placeholders::_2)); } // virtual diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index bcaf479b0f..749999bbfe 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -31,7 +31,8 @@ //#include "llboost.h" #include "llrect.h" #include "llsd.h" -#include <boost/function.hpp> +#include <functional> +#include <boost/bind.hpp> #include <boost/signals2.hpp> #include "llinitparam.h" @@ -47,12 +48,12 @@ class LLUICtrl : public LLView, public boost::signals2::trackable { public: - typedef boost::function<void (LLUICtrl* ctrl, const LLSD& param)> commit_callback_t; + typedef std::function<void (LLUICtrl* ctrl, const LLSD& param)> commit_callback_t; typedef boost::signals2::signal<void (LLUICtrl* ctrl, const LLSD& param)> commit_signal_t; // *TODO: add xml support for this type of signal in the future typedef boost::signals2::signal<void (LLUICtrl* ctrl, S32 x, S32 y, MASK mask)> mouse_signal_t; - typedef boost::function<bool (LLUICtrl* ctrl, const LLSD& param)> enable_callback_t; + typedef std::function<bool (LLUICtrl* ctrl, const LLSD& param)> enable_callback_t; typedef boost::signals2::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t; struct CallbackParam : public LLInitParam::Block<CallbackParam> @@ -258,8 +259,8 @@ public: boost::signals2::connection setDoubleClickCallback( const mouse_signal_t::slot_type& cb ); // *TODO: Deprecate; for backwards compatability only: - boost::signals2::connection setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data); - boost::signals2::connection setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb ); + boost::signals2::connection setCommitCallback( std::function<void (LLUICtrl*,void*)> cb, void* data); + boost::signals2::connection setValidateBeforeCommit( std::function<bool (const LLSD& data)> cb ); LLUICtrl* findRootMostFocusRoot(); diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index a2a6d661ff..9abccfd9a0 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -100,16 +100,19 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa std::string base_filename = search_paths.front(); if (!base_filename.empty()) { - LLUICtrlFactory::instance().pushFileName(base_filename); + LLUICtrlFactory *factory = LLUICtrlFactory::getInstance(); + factory->mFileNames.push_back(base_filename); - if (!LLXMLNode::getLayeredXMLNode(root_node, search_paths)) + if (LLXMLNode::getLayeredXMLNode(root_node, search_paths)) + { + LLXUIParser parser; + parser.readXUI(root_node, block, base_filename); + } + else { LL_WARNS() << "Couldn't parse widget from: " << base_filename << LL_ENDL; - return; } - LLXUIParser parser; - parser.readXUI(root_node, block, base_filename); - LLUICtrlFactory::instance().popFileName(); + factory->mFileNames.pop_back(); } } diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 91221dc7f3..fc069c078f 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -311,7 +311,7 @@ LLUICtrlFactory::ParamDefaults<LLInitParam::BaseBlock, DUMMY>::ParamDefaults() { template<typename DERIVED> template<typename T> LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreatorFunc func) -: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func) +: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func == nullptr ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func) { // add this widget to various registries LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag); diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index b6b450c2a1..8b320b59cc 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -30,6 +30,7 @@ #include "llview.h" #include "llwindow.h" #include "llurlregistry.h" +#include "v3dmath.h" // global state for the callback functions @@ -116,6 +117,16 @@ void LLUrlAction::teleportToLocation(std::string url) } } +void LLUrlAction::zoomInObject(std::string url) +{ + LLUrlMatch match; + std::string object_id = getObjectId(url); + if (LLUUID::validate(object_id) && LLUrlRegistry::instance().findUrl(url, match)) + { + executeSLURL("secondlife:///app/object/" + object_id + "/zoomin/" + match.getLocation()); + } +} + void LLUrlAction::showLocationOnMap(std::string url) { LLUrlMatch match; @@ -128,6 +139,23 @@ void LLUrlAction::showLocationOnMap(std::string url) } } +void LLUrlAction::showParcelOnMap(std::string url) +{ + LLSD path_array = LLURI(url).pathArray(); + auto path_parts = path_array.size(); + + if (path_parts < 3) // no parcel id + { + LL_WARNS() << "Global coordinates are missing in url: [" << url << "]" << LL_ENDL; + return; + } + + LLVector3d parcel_pos = LLUrlEntryParcel::getParcelPos(LLUUID(LLURI::unescape(path_array[2]))); + std::ostringstream pos; + pos << parcel_pos.mdV[VX] << '/' << parcel_pos.mdV[VY] << '/' << parcel_pos.mdV[VZ]; + executeSLURL("secondlife:///app/worldmap_global/" + pos.str()); +} + void LLUrlAction::copyURLToClipboard(std::string url) { LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(url)); @@ -142,6 +170,16 @@ void LLUrlAction::copyLabelToClipboard(std::string url) } } +std::string LLUrlAction::getURLLabel(std::string url) +{ + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + return match.getLabel(); + } + return ""; +} + void LLUrlAction::showProfile(std::string url) { // Get id from 'secondlife:///app/{cmd}/{id}/{action}' diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index ac9741a7ad..c4cfd0f3fb 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -28,8 +28,8 @@ #ifndef LL_LLURLACTION_H #define LL_LLURLACTION_H +#include <functional> #include <string> -#include <boost/function.hpp> /// /// The LLUrlAction class provides a number of static functions that @@ -60,9 +60,15 @@ public: /// if the Url specifies an SL location, teleport there static void teleportToLocation(std::string url); + /// If the Url specifies an object id, attempt to zoom in. + /// If not possible to zoom in, show on map + static void zoomInObject(std::string url); + /// if the Url specifies an SL location, show it on a map static void showLocationOnMap(std::string url); + static void showParcelOnMap(std::string url); + /// perform the appropriate action for left-clicking on a Url static void clickAction(std::string url, bool trusted_content); @@ -72,6 +78,8 @@ public: /// copy a Url to the clipboard static void copyURLToClipboard(std::string url); + static std::string getURLLabel(std::string url); + /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile static void showProfile(std::string url); static std::string getUserID(std::string url); @@ -85,8 +93,8 @@ public: static void unblockObject(std::string url); /// specify the callbacks to enable this class's functionality - typedef boost::function<void (const std::string&)> url_callback_t; - typedef boost::function<bool(const std::string& url, bool trusted_content)> execute_url_callback_t; + typedef std::function<void (const std::string&)> url_callback_t; + typedef std::function<bool(const std::string& url, bool trusted_content)> execute_url_callback_t; static void setOpenURLCallback(url_callback_t cb); static void setOpenURLInternalCallback(url_callback_t cb); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index bcd13b7f0b..bba80dd20e 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -41,8 +41,7 @@ #include "lluicolortable.h" #include "message.h" #include "llexperiencecache.h" - -#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" +#include "v3dmath.h" // Utility functions std::string localize_slapp_label(const std::string& url, const std::string& full_name); @@ -235,7 +234,7 @@ bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const || label.find("www.") != std::string::npos) && label.find("://") == std::string::npos) { - label = "http://" + label; + label = "https://" + label; } return !LLUrlRegistry::instance().hasUrl(label); @@ -316,7 +315,7 @@ std::string LLUrlEntryHTTP::getUrl(const std::string &string) const { if (string.find("://") == std::string::npos) { - return "http://" + escapeUrl(string); + return "https://" + escapeUrl(string); } return escapeUrl(string); } @@ -1084,6 +1083,7 @@ LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null); LLHost LLUrlEntryParcel::sRegionHost; bool LLUrlEntryParcel::sDisconnected(false); std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers; +std::map<LLUUID, LLVector3d> LLUrlEntryParcel::sParcelPos; /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., @@ -1176,6 +1176,20 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label); } } + if (sParcelPos.find(parcel_data.parcel_id) == sParcelPos.end()) + { + sParcelPos[parcel_data.parcel_id] = LLVector3d(parcel_data.global_x, parcel_data.global_y, parcel_data.global_z); + } +} + +// static +LLVector3d LLUrlEntryParcel::getParcelPos(const LLUUID& parcel_id) +{ + if (sParcelPos.find(parcel_id) != sParcelPos.end()) + { + return sParcelPos[parcel_id]; + } + return LLVector3d(); } // diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 6e7d2fc80f..efb5081103 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -41,6 +41,9 @@ #include <map> class LLAvatarName; +class LLVector3d; + +#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" typedef boost::signals2::signal<void (const std::string& url, const std::string& label, @@ -434,6 +437,8 @@ public: // Processes parcel label and triggers notifying observers. static void processParcelInfo(const LLParcelData& parcel_data); + static LLVector3d getParcelPos(const LLUUID& parcel_id); + // 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 @@ -447,6 +452,7 @@ private: static LLHost sRegionHost; static bool sDisconnected; static std::set<LLUrlEntryParcel*> sParcelInfoObservers; + static std::map<LLUUID, LLVector3d> sParcelPos; }; /// diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 97212a9d2d..d747ef9555 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -48,9 +48,8 @@ #include "lltreeiterators.h" #include "llfocusmgr.h" +#include <functional> #include <list> -#include <boost/function.hpp> -#include <boost/noncopyable.hpp> class LLSD; @@ -627,7 +626,7 @@ private: LLView& getDefaultWidgetContainer() const; // This allows special mouse-event targeting logic for testing. - typedef boost::function<bool(const LLView*, S32 x, S32 y)> DrilldownFunc; + typedef std::function<bool(const LLView*, S32 x, S32 y)> DrilldownFunc; static DrilldownFunc sDrilldown; public: @@ -637,7 +636,7 @@ public: // LLView::TemporaryDrilldownFunc scoped_func(myfunctor); // // ... test with myfunctor ... // } // exiting block restores original LLView::sDrilldown - class TemporaryDrilldownFunc: public boost::noncopyable + class TemporaryDrilldownFunc { public: TemporaryDrilldownFunc(const DrilldownFunc& func): @@ -651,6 +650,10 @@ public: sDrilldown = mOldDrilldown; } + // Non-copyable + TemporaryDrilldownFunc(const TemporaryDrilldownFunc&) = delete; + TemporaryDrilldownFunc& operator=(const TemporaryDrilldownFunc&) = delete; + private: DrilldownFunc mOldDrilldown; }; diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp index 6d907d7e45..9eefba1390 100644 --- a/indra/llui/llviewereventrecorder.cpp +++ b/indra/llui/llviewereventrecorder.cpp @@ -34,8 +34,6 @@ LLViewerEventRecorder::LLViewerEventRecorder() { logEvents = false; // Remove any previous event log file std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old"); - LLFile::remove(old_log_ui_events_to_llsd_file, ENOENT); - mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd"); LLFile::rename(mLogFilename, old_log_ui_events_to_llsd_file, ENOENT); 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/llxuiparser.h b/indra/llui/llxuiparser.h index f755c12cbf..2179ae54d3 100644 --- a/indra/llui/llxuiparser.h +++ b/indra/llui/llxuiparser.h @@ -31,7 +31,7 @@ #include "llregistry.h" #include "llxmlnode.h" -#include <boost/function.hpp> +#include <functional> #include <iosfwd> #include <stack> #include <set> @@ -47,7 +47,7 @@ class LLWidgetTypeRegistry // global static instance for registering all widget types -typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc; +typedef std::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc; typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t; |
