From 3654ff5f5c056bebb212a0f94c43694bec4bf42b Mon Sep 17 00:00:00 2001 From: Lirusaito Date: Mon, 22 Jul 2019 08:39:06 -0400 Subject: [PATCH] Fix up EAM to work (Part 2) Did you know you could type into a list to search it by prefix?! The Lindens didn't!! Let's make this search bar an ACTUAL FILTER! To do this, we add support for filtering to all scroll lists, so that's cool. Also filtered items will be selected. Also optimized item selection loop to perform better when selecting in massive lists (like group members) Changed the text on the Copy Button to reflect that it copies everything, not just the applied filter... if you wanted that, you could just ctrl-a, ctrl-c... I mean, reallly --- indra/llui/llscrolllistctrl.cpp | 155 ++++++++++++------ indra/llui/llscrolllistctrl.h | 5 + indra/llui/llscrolllistitem.cpp | 1 + indra/llui/llscrolllistitem.h | 4 + indra/newview/llfloaterregioninfo.cpp | 11 +- .../default/xui/en-us/panel_region_access.xml | 6 +- 6 files changed, 120 insertions(+), 62 deletions(-) diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 04c635f2a..ef1fe5214 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -54,6 +54,8 @@ #include "llsdparam.h" #include "llmenugl.h" +#include + static LLRegisterWidget r("scroll_list"); @@ -504,6 +506,8 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r BOOL not_too_big = getItemCount() < mMaxItemCount; if (not_too_big) { + if (!mFilter.empty()) filterItem(item); + switch( pos ) { case ADD_TOP: @@ -586,10 +590,11 @@ S32 LLScrollListCtrl::calcMaxContentWidth() { // update max content width for this column, by looking at all items column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel.getWString()) + mColumnPadding + HEADING_TEXT_PADDING : 0; - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (auto& item : mItemList) { - LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex); + if (item->getFiltered()) continue; + + LLScrollListCell* cellp = item->getColumn(column->mIndex); if (!cellp) continue; column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth); @@ -642,10 +647,8 @@ const S32 SCROLL_LIST_ROW_PAD = 2; void LLScrollListCtrl::updateLineHeight() { mLineHeight = 0; - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (auto& itemp : mItemList) { - LLScrollListItem *itemp = *iter; S32 num_cols = itemp->getNumColumns(); S32 i = 0; for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) @@ -766,6 +769,7 @@ BOOL LLScrollListCtrl::selectFirstItem() for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem *itemp = *iter; + if (itemp->getFiltered()) continue; if( first_item && itemp->getEnabled() ) { if (!itemp->getSelected()) @@ -824,20 +828,23 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index ) iter = mItemList.erase(iter); continue ; } - - if( index >= first_index && index <= last_index ) + + if (itemp->getFiltered()) { - if( itemp->getEnabled() ) + if (index >= first_index && index <= last_index) { - selectItem(itemp, FALSE); - success = TRUE; + if (itemp->getEnabled()) + { + selectItem(itemp, FALSE); + success = TRUE; + } } + else + { + deselectItem(itemp); + } + index++; } - else - { - deselectItem(itemp); - } - index++; iter++ ; } @@ -973,6 +980,8 @@ S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids ) for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; + if (item->getFiltered()) continue; + uuid_vec_t::iterator iditr; for(iditr = ids.begin(); iditr != ids.end(); ++iditr) { @@ -998,15 +1007,14 @@ S32 LLScrollListCtrl::getItemIndex( LLScrollListItem* target_item ) const updateSort(); S32 index = 0; - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* itemp : mItemList) { - LLScrollListItem *itemp = *iter; + if (itemp->getFiltered()) continue; if (target_item == itemp) { return index; } - index++; + ++index; } return -1; } @@ -1016,15 +1024,14 @@ S32 LLScrollListCtrl::getItemIndex( const LLUUID& target_id ) const updateSort(); S32 index = 0; - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* itemp : mItemList) { - LLScrollListItem *itemp = *iter; + if (itemp->getFiltered()) continue; if (target_id == itemp->getUUID()) { return index; } - index++; + ++index; } return -1; } @@ -1046,6 +1053,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection) for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* cur_item = *iter; + if (cur_item->getFiltered()) continue; if (cur_item->getSelected()) { @@ -1090,6 +1098,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection) for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++) { LLScrollListItem* cur_item = *iter; + if (cur_item->getFiltered()) continue; if (cur_item->getSelected()) { @@ -1194,6 +1203,8 @@ LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, BOO for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; + if (item->getFiltered()) continue; + std::string item_text = item->getColumn(column)->getValue().asString(); // Only select enabled items with matching names if (!case_sensitive) { @@ -1229,6 +1240,8 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; + if (item->getFiltered()) continue; + // Only select enabled items with matching names LLScrollListCell* cellp = item->getColumn(getSearchColumn()); BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; @@ -1252,6 +1265,9 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen { LLScrollListItem* item = *iter; + // Don't select filtered items + if (item->getFiltered()) continue; + // Only select enabled items with matching names LLScrollListCell* cellp = item->getColumn(getSearchColumn()); if (!cellp) @@ -1336,6 +1352,8 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected) for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; + if (item->getFiltered()) continue; + if (item->getEnabled() && (item->getValue().asString() == value.asString())) { if (selected) @@ -1365,7 +1383,7 @@ BOOL LLScrollListCtrl::isSelected(const LLSD& value) const for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; - if (item->getValue().asString() == value.asString()) + if (!item->getFiltered() && item->getValue().asString() == value.asString()) { return item->getSelected(); } @@ -1443,9 +1461,10 @@ void LLScrollListCtrl::drawItems() { bool should_continue = false; // False until all passes are done for all row cells. S32 cur_y = y; - for (S32 line = first_line; line <= last_line; line++) + for (S32 index = first_line, line = first_line; index <= last_line; ++index) { - LLScrollListItem* item = mItemList[line]; + LLScrollListItem* item = mItemList[index]; + if (item->getFiltered()) continue; // Skip filtered item_rect.setOriginAndSize( x, @@ -1498,6 +1517,7 @@ void LLScrollListCtrl::drawItems() should_continue |= item->draw(pass, item_rect, fg_color, bg_color, highlight_color, mColumnPadding); } + ++line; } done = !should_continue; } @@ -1647,9 +1667,10 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) // meaning that we never stop selecting until hitting max or // the end of the list. LLScrollListItem* lastSelected = mLastSelected; + auto selected_count = getAllSelected().size(); for (itor = mItemList.begin(); itor != mItemList.end(); ++itor) { - if(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable) + if(mMaxSelectable > 0 && selected_count >= mMaxSelectable) { if(mOnMaximumSelectCallback) { @@ -1658,6 +1679,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) break; } LLScrollListItem *item = *itor; + if (item->getFiltered()) continue; if (item == hit_item || item == lastSelected) { selectItem(item, FALSE); @@ -1672,6 +1694,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { selectItem(item, FALSE); } + ++selected_count; } } } @@ -1884,10 +1907,9 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) S32 num_page_lines = getLinesPerPage(); S32 line = 0; - item_list::iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + for(LLScrollListItem* item : mItemList) { - LLScrollListItem* item = *iter; + if (item->getFiltered()) continue; if( mScrollLines <= line && line < mScrollLines + num_page_lines ) { if( item->getEnabled() && item_rect.pointInRect( x, y ) ) @@ -1898,7 +1920,7 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) item_rect.translate(0, -mLineHeight); } - line++; + ++line; } return hit_item; @@ -1956,6 +1978,39 @@ S32 LLScrollListCtrl::getRowOffsetFromIndex(S32 index) return row_bottom; } +void LLScrollListCtrl::filterItem(LLScrollListItem* item) +{ + for (const auto& column : item->mColumns) + { + // Only filter text, search tooltip because it'll usually be the text anyway. + if (column->isText() && boost::icontains(column->getToolTip(), mFilter)) + { + item->setFiltered(false); + return; + } + } + item->setFiltered(true); +} + +void LLScrollListCtrl::setFilter(const std::string& filter) +{ + if (filter == mFilter) return; + + bool no_filter = filter.empty(); + // If our filter string has been expanded, we can skip already filtered items + bool expanded = !no_filter && !mFilter.empty() && boost::icontains(filter, mFilter); + + mFilter = filter; + for (auto& item : mItemList) + { + if (no_filter) item->setFiltered(false); + else if (!expanded || !item->getFiltered()) + { + filterItem(item); + } + } +} + BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) { @@ -2185,26 +2240,28 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char) while(iter != start_iter) { LLScrollListItem* item = *iter; - - LLScrollListCell* cellp = item->getColumn(getSearchColumn()); - if (cellp) + if (!item->getFiltered()) { - // Only select enabled items with matching first characters - LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); - if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) + LLScrollListCell* cellp = item->getColumn(getSearchColumn()); + if (cellp) { - selectItem(item); - mNeedsScroll = true; - cellp->highlightText(0, 1); - mSearchTimer.reset(); - - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) + // Only select enabled items with matching first characters + LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); + if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) { - onCommit(); - } + selectItem(item); + mNeedsScroll = true; + cellp->highlightText(0, 1); + mSearchTimer.reset(); - break; + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + + break; + } } } @@ -2816,7 +2873,7 @@ void LLScrollListCtrl::selectAll() for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem *itemp = *iter; - if( itemp->getEnabled() ) + if (itemp->getEnabled() && !itemp->getFiltered()) { selectItem(itemp, FALSE); } diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index d5ffb9df9..d53aa5d4e 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -249,6 +249,9 @@ public: void clearSearchString() { mSearchString.clear(); } + void filterItem(LLScrollListItem* item); + void setFilter(const std::string& filter); + // support right-click context menus for avatar/group lists void setContextMenu(LLMenuGL* menu) { mPopupMenu = menu; } void setContextMenu(S32 index) { mPopupMenu = sMenus[index]; } @@ -468,6 +471,8 @@ private: LLWString mSearchString; LLFrameTimer mSearchTimer; + + std::string mFilter; S32 mSearchColumn; S32 mNumDynamicWidthColumns; diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp index c490a5249..d6d3cf2aa 100644 --- a/indra/llui/llscrolllistitem.cpp +++ b/indra/llui/llscrolllistitem.cpp @@ -38,6 +38,7 @@ LLScrollListItem::LLScrollListItem( const Params& p ) : mSelected(FALSE), mEnabled(p.enabled), + mFiltered(false), mUserdata(p.userdata), mItemValue(p.value), mColumns() diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h index a1229e034..f291b7cf2 100644 --- a/indra/llui/llscrolllistitem.h +++ b/indra/llui/llscrolllistitem.h @@ -71,6 +71,9 @@ public: void setEnabled( BOOL b ) { mEnabled = b; } BOOL getEnabled() const { return mEnabled; } + void setFiltered(bool b) { if (mFiltered = b) mSelected = false; } + bool getFiltered() const { return mFiltered; } + void setUserdata( void* userdata ) { mUserdata = userdata; } void* getUserdata() const { return mUserdata; } @@ -100,6 +103,7 @@ protected: private: BOOL mSelected; BOOL mEnabled; + bool mFiltered; void* mUserdata; LLSD mItemValue; std::vector mColumns; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 722c1a31c..37be6ed3b 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -4250,16 +4250,7 @@ void LLPanelEstateAccess::onBannedSearchEdit(const std::string& search_string) void LLPanelEstateAccess::searchAgent(LLNameListCtrl* listCtrl, const std::string& search_string) { if (!listCtrl) return; - - if (!search_string.empty()) - { - listCtrl->setSearchColumn(0); // name column - listCtrl->selectItemByPrefix(search_string, FALSE); - } - else - { - listCtrl->deselectAllItems(TRUE); - } + listCtrl->setFilter(search_string); } void LLPanelEstateAccess::copyListToClipboard(std::string list_name) diff --git a/indra/newview/skins/default/xui/en-us/panel_region_access.xml b/indra/newview/skins/default/xui/en-us/panel_region_access.xml index c551d82f8..a7bb54ea1 100644 --- a/indra/newview/skins/default/xui/en-us/panel_region_access.xml +++ b/indra/newview/skins/default/xui/en-us/panel_region_access.xml @@ -216,7 +216,7 @@ follows="left|top" bottom_delta="0" height="23" - label="Copy" + label="Copy All" layout="topleft" left_delta="123" name="copy_allowed_list_btn" @@ -328,7 +328,7 @@ follows="left|top" bottom_delta="0" height="23" - label="Copy" + label="Copy All" layout="topleft" left_delta="123" name="copy_allowed_group_list_btn" @@ -454,7 +454,7 @@ follows="left|top" bottom_delta="0" height="23" - label="Copy" + label="Copy All" layout="topleft" left_delta="123" name="copy_banned_list_btn"