summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
authorKitty Barnett <develop@catznip.com>2023-02-08 14:56:38 +0100
committerKitty Barnett <develop@catznip.com>2023-02-08 14:56:38 +0100
commit7b563470fbade848d7eeb52d5088f3ca9b9c6905 (patch)
treedc3faed194d6ce8cc8d5b18175dfad17a1490cd8 /indra/llui
parentf3cd329b585ef55a66f2a824f010d1a54d67d8d2 (diff)
parent8d21d29bd7fa038db632ff90fb0e1207d0713ca2 (diff)
Merge branch 'main' into xcode-14.1
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llchat.h3
-rw-r--r--indra/llui/llcheckboxctrl.cpp6
-rw-r--r--indra/llui/llflatlistview.cpp11
-rw-r--r--indra/llui/llflatlistview.h1
-rw-r--r--indra/llui/llfolderview.cpp58
-rw-r--r--indra/llui/llfolderview.h3
-rw-r--r--indra/llui/llfolderviewmodel.h18
-rw-r--r--indra/llui/lllineeditor.cpp18
-rw-r--r--indra/llui/llmenugl.cpp58
-rw-r--r--indra/llui/llmenugl.h3
-rw-r--r--indra/llui/llmultislider.cpp2
-rw-r--r--indra/llui/llscrolllistctrl.cpp77
-rw-r--r--indra/llui/llscrolllistctrl.h8
-rw-r--r--indra/llui/llspinctrl.cpp7
-rw-r--r--indra/llui/lltabcontainer.cpp5
-rw-r--r--indra/llui/lltextbase.cpp203
-rw-r--r--indra/llui/lltextbase.h2
-rw-r--r--indra/llui/lltexteditor.cpp31
-rw-r--r--indra/llui/lltexteditor.h2
-rw-r--r--indra/llui/lltoolbar.cpp7
20 files changed, 344 insertions, 179 deletions
diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h
index c39e44200c..b4fd5f60aa 100644
--- a/indra/llui/llchat.h
+++ b/indra/llui/llchat.h
@@ -38,7 +38,8 @@ typedef enum e_chat_source_type
CHAT_SOURCE_AGENT = 1,
CHAT_SOURCE_OBJECT = 2,
CHAT_SOURCE_TELEPORT = 3,
- CHAT_SOURCE_UNKNOWN = 4
+ CHAT_SOURCE_UNKNOWN = 4,
+ CHAT_SOURCE_REGION = 5,
} EChatSourceType;
typedef enum e_chat_type
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index 08da599ef2..362fe0c19e 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -203,11 +203,9 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
// it will work fine in case of decrease of space, but if we get more space or text
// becomes longer, label will fail to grow so reinit label's dimentions.
- static LLUICachedControl<S32> llcheckboxctrl_hpad("UICheckboxctrlHPad", 0);
LLRect label_rect = mLabel->getRect();
- S32 new_width = getRect().getWidth() - label_rect.mLeft - llcheckboxctrl_hpad;
- label_rect.mRight = label_rect.mLeft + new_width;
- mLabel->setRect(label_rect);
+ S32 new_width = rect.getWidth() - label_rect.mLeft;
+ mLabel->reshape(new_width, label_rect.getHeight(), TRUE);
S32 label_top = label_rect.mTop;
mLabel->reshapeToFitText(TRUE);
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index 5e00bf7f45..b13e7389cc 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -505,6 +505,17 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p)
}
};
+LLFlatListView::~LLFlatListView()
+{
+ for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it)
+ {
+ mItemsPanel->removeChild((*it)->first);
+ (*it)->first->die();
+ delete *it;
+ }
+ mItemPairs.clear();
+}
+
// virtual
void LLFlatListView::draw()
{
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index 230ea200d8..d47c1cf333 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -299,6 +299,7 @@ public:
virtual S32 notify(const LLSD& info) ;
+ virtual ~LLFlatListView();
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index ea2ca68e47..e1869e8125 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -163,6 +163,7 @@ LLFolderView::LLFolderView(const Params& p)
: LLFolderViewFolder(p),
mScrollContainer( NULL ),
mPopupMenuHandle(),
+ mMenuFileName(p.options_menu),
mAllowMultiSelect(p.allow_multiselect),
mAllowDrag(p.allow_drag),
mShowEmptyMessage(p.show_empty_message),
@@ -182,6 +183,7 @@ LLFolderView::LLFolderView(const Params& p)
mMinWidth(0),
mDragAndDropThisFrame(FALSE),
mCallbackRegistrar(NULL),
+ mEnableRegistrar(NULL),
mUseEllipses(p.use_ellipses),
mDraggingOverItem(NULL),
mStatusTextBox(NULL),
@@ -244,17 +246,6 @@ LLFolderView::LLFolderView(const Params& p)
mStatusTextBox->setFollowsTop();
addChild(mStatusTextBox);
-
- // make the popup menu available
- llassert(LLMenuGL::sMenuContainer != NULL);
- LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(p.options_menu, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
- if (!menu)
- {
- menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
- }
- menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor"));
- mPopupMenuHandle = menu->getHandle();
-
mViewModelItem->openItem();
mAreChildrenInited = true; // root folder is a special case due to not being loaded normally, assume that it's inited.
@@ -276,6 +267,7 @@ LLFolderView::~LLFolderView( void )
mStatusTextBox = NULL;
if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die();
+ mPopupMenuHandle.markDead();
mAutoOpenItems.removeAllNodes();
clearSelection();
@@ -1438,22 +1430,56 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL;
S32 count = mSelectedItems.size();
- LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
+ LLMenuGL* menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get());
+ if (!menu)
+ {
+ if (mCallbackRegistrar)
+ {
+ mCallbackRegistrar->pushScope();
+ }
+ if (mEnableRegistrar)
+ {
+ mEnableRegistrar->pushScope();
+ }
+ llassert(LLMenuGL::sMenuContainer != NULL);
+ menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(mMenuFileName, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ if (!menu)
+ {
+ menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
+ }
+ menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor"));
+ mPopupMenuHandle = menu->getHandle();
+ if (mEnableRegistrar)
+ {
+ mEnableRegistrar->popScope();
+ }
+ if (mCallbackRegistrar)
+ {
+ mCallbackRegistrar->popScope();
+ }
+ }
bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected();
- if ((handled
- && ( count > 0 && (hasVisibleChildren()) ) // show menu only if selected items are visible
- && menu ) &&
+ if (menu && (handled
+ && ( count > 0 && (hasVisibleChildren()) )) && // show menu only if selected items are visible
!hide_folder_menu)
{
if (mCallbackRegistrar)
{
mCallbackRegistrar->pushScope();
}
+ if (mEnableRegistrar)
+ {
+ mEnableRegistrar->pushScope();
+ }
updateMenuOptions(menu);
menu->updateParent(LLMenuGL::sMenuContainer);
LLMenuGL::showPopup(this, menu, x, y);
+ if (mEnableRegistrar)
+ {
+ mEnableRegistrar->popScope();
+ }
if (mCallbackRegistrar)
{
mCallbackRegistrar->popScope();
@@ -1531,7 +1557,7 @@ void LLFolderView::deleteAllChildren()
{
closeRenamer();
if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die();
- mPopupMenuHandle = LLHandle<LLView>();
+ mPopupMenuHandle.markDead();
mScrollContainer = NULL;
mRenameItem = NULL;
mRenamer = NULL;
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index 6bb5e6c02e..7dfa04828a 100644
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -235,6 +235,7 @@ public:
bool showItemLinkOverlays() { return mShowItemLinkOverlays; }
void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; }
+ void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; }
LLPanel* getParentPanel() { return mParentPanel.get(); }
// DEBUG only
@@ -272,6 +273,7 @@ protected:
protected:
LLHandle<LLView> mPopupMenuHandle;
+ std::string mMenuFileName;
selected_items_t mSelectedItems;
bool mKeyboardSelection,
@@ -327,6 +329,7 @@ protected:
LLFolderViewItem* mDraggingOverItem; // See EXT-719
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
public:
static F32 sAutoOpenTime;
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index 093e213be3..c5e027d314 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -172,7 +172,7 @@ public:
virtual BOOL removeItem() = 0;
virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0;
- virtual BOOL isItemCopyable() const = 0;
+ virtual bool isItemCopyable(bool can_copy_as_link = true) const = 0;
virtual BOOL copyToClipboard() const = 0;
virtual BOOL cutToClipboard() = 0;
virtual bool isCutToClipboard() { return false; };
@@ -419,21 +419,15 @@ public:
mFilter(filter)
{}
- virtual ~LLFolderViewModel()
- {
- delete mSorter;
- mSorter = NULL;
- delete mFilter;
- mFilter = NULL;
- }
+ virtual ~LLFolderViewModel() {}
virtual SortType& getSorter() { return *mSorter; }
virtual const SortType& getSorter() const { return *mSorter; }
- virtual void setSorter(const SortType& sorter) { mSorter = new SortType(sorter); requestSortAll(); }
+ virtual void setSorter(const SortType& sorter) { mSorter.reset(new SortType(sorter)); requestSortAll(); }
virtual FilterType& getFilter() { return *mFilter; }
virtual const FilterType& getFilter() const { return *mFilter; }
- virtual void setFilter(const FilterType& filter) { mFilter = new FilterType(filter); }
+ virtual void setFilter(const FilterType& filter) { mFilter.reset(new 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.
@@ -471,8 +465,8 @@ public:
}
protected:
- SortType* mSorter;
- FilterType* mFilter;
+ std::unique_ptr<SortType> mSorter;
+ std::unique_ptr<FilterType> mFilter;
};
#endif // LLFOLDERVIEWMODEL_H
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 33037b5001..940cf398c0 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -209,13 +209,6 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
setPrevalidateInput(p.prevalidate_input_callback());
setPrevalidate(p.prevalidate_callback());
-
- llassert(LLMenuGL::sMenuContainer != NULL);
- LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>
- ("menu_text_editor.xml",
- LLMenuGL::sMenuContainer,
- LLMenuHolderGL::child_registry_t::instance());
- setContextMenu(menu);
}
LLLineEditor::~LLLineEditor()
@@ -1567,7 +1560,7 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask )
KEY_SHIFT != key &&
KEY_CONTROL != key &&
KEY_ALT != key &&
- KEY_CAPSLOCK )
+ KEY_CAPSLOCK != key)
{
deselect();
}
@@ -2637,6 +2630,15 @@ LLWString LLLineEditor::getConvertedText() const
void LLLineEditor::showContextMenu(S32 x, S32 y)
{
LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get());
+ if (!menu)
+ {
+ llassert(LLMenuGL::sMenuContainer != NULL);
+ menu = LLUICtrlFactory::createFromFile<LLContextMenu>
+ ("menu_text_editor.xml",
+ LLMenuGL::sMenuContainer,
+ LLMenuHolderGL::child_registry_t::instance());
+ setContextMenu(menu);
+ }
if (menu)
{
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 4264028338..5cb840fd61 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -4087,25 +4087,39 @@ void LLTearOffMenu::closeTearOff()
}
LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p)
-: LLMenuItemGL(p),
- mBranch( p.branch()->getHandle() )
+: LLMenuItemGL(p)
{
- mBranch.get()->hide();
- mBranch.get()->setParentMenuItem(this);
+ LLContextMenu* branch = static_cast<LLContextMenu*>(p.branch);
+ if (branch)
+ {
+ mBranch = branch->getHandle();
+ branch->hide();
+ branch->setParentMenuItem(this);
+ }
+}
+
+LLContextMenuBranch::~LLContextMenuBranch()
+{
+ if (mBranch.get())
+ {
+ mBranch.get()->die();
+ }
}
// called to rebuild the draw label
void LLContextMenuBranch::buildDrawLabel( void )
{
+ auto menu = getBranch();
+ if (menu)
{
// default enablement is this -- if any of the subitems are
// enabled, this item is enabled. JC
- U32 sub_count = mBranch.get()->getItemCount();
+ U32 sub_count = menu->getItemCount();
U32 i;
BOOL any_enabled = FALSE;
for (i = 0; i < sub_count; i++)
{
- LLMenuItemGL* item = mBranch.get()->getItem(i);
+ LLMenuItemGL* item = menu->getItem(i);
item->buildDrawLabel();
if (item->getEnabled() && !item->getDrawTextDisabled() )
{
@@ -4127,13 +4141,17 @@ void LLContextMenuBranch::buildDrawLabel( void )
void LLContextMenuBranch::showSubMenu()
{
- LLMenuItemGL* menu_item = mBranch.get()->getParentMenuItem();
- if (menu_item != NULL && menu_item->getVisible())
+ auto menu = getBranch();
+ if(menu)
{
- S32 center_x;
- S32 center_y;
- localPointToScreen(getRect().getWidth(), getRect().getHeight() , &center_x, &center_y);
- mBranch.get()->show(center_x, center_y);
+ LLMenuItemGL* menu_item = menu->getParentMenuItem();
+ if (menu_item != NULL && menu_item->getVisible())
+ {
+ S32 center_x;
+ S32 center_y;
+ localPointToScreen(getRect().getWidth(), getRect().getHeight(), &center_x, &center_y);
+ menu->show(center_x, center_y);
+ }
}
}
@@ -4147,13 +4165,17 @@ void LLContextMenuBranch::setHighlight( BOOL highlight )
{
if (highlight == getHighlight()) return;
LLMenuItemGL::setHighlight(highlight);
- if( highlight )
- {
- showSubMenu();
- }
- else
+ auto menu = getBranch();
+ if (menu)
{
- mBranch.get()->hide();
+ if (highlight)
+ {
+ showSubMenu();
+ }
+ else
+ {
+ menu->hide();
+ }
}
}
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index abbfd9a24a..f84c4d41eb 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -745,8 +745,7 @@ public:
LLContextMenuBranch(const Params&);
- virtual ~LLContextMenuBranch()
- {}
+ virtual ~LLContextMenuBranch();
// called to rebuild the draw label
virtual void buildDrawLabel( void );
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
index f89064d59a..604d246f12 100644
--- a/indra/llui/llmultislider.cpp
+++ b/indra/llui/llmultislider.cpp
@@ -92,7 +92,7 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
mMouseDownSignal(NULL),
mMouseUpSignal(NULL)
{
- mValue.emptyMap();
+ mValue = LLSD::emptyMap();
mCurSlider = LLStringUtil::null;
if (mOrientation == HORIZONTAL)
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 65c7b420ce..219667f766 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -196,7 +196,6 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
mHighlightedItem(-1),
mBorder(NULL),
mSortCallback(NULL),
- mPopupMenu(NULL),
mCommentTextView(NULL),
mNumDynamicWidthColumns(0),
mTotalStaticColumnWidth(0),
@@ -348,6 +347,13 @@ LLScrollListCtrl::~LLScrollListCtrl()
mItemList.clear();
clearColumns(); //clears columns and deletes headers
delete mIsFriendSignal;
+
+ auto menu = mPopupMenuHandle.get();
+ if (menu)
+ {
+ menu->die();
+ mPopupMenuHandle.markDead();
+ }
}
@@ -1307,14 +1313,14 @@ LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, BOO
}
-BOOL LLScrollListCtrl::selectItemByPrefix(const std::string& target, BOOL case_sensitive)
+BOOL LLScrollListCtrl::selectItemByPrefix(const std::string& target, BOOL case_sensitive, S32 column)
{
- return selectItemByPrefix(utf8str_to_wstring(target), case_sensitive);
+ return selectItemByPrefix(utf8str_to_wstring(target), case_sensitive, column);
}
// Selects first enabled item that has a name where the name's first part matched the target string.
// Returns false if item not found.
-BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sensitive)
+BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sensitive, S32 column)
{
BOOL found = FALSE;
@@ -1329,7 +1335,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
{
LLScrollListItem* item = *iter;
// Only select enabled items with matching names
- LLScrollListCell* cellp = item->getColumn(getSearchColumn());
+ LLScrollListCell* cellp = item->getColumn(column == -1 ? getSearchColumn() : column);
BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
if (select)
{
@@ -1352,7 +1358,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
LLScrollListItem* item = *iter;
// Only select enabled items with matching names
- LLScrollListCell* cellp = item->getColumn(getSearchColumn());
+ LLScrollListCell* cellp = item->getColumn(column == -1 ? getSearchColumn() : column);
if (!cellp)
{
continue;
@@ -1997,17 +2003,23 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
// create the context menu from the XUI file and display it
std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml";
- delete mPopupMenu;
+ auto menu = mPopupMenuHandle.get();
+ if (menu)
+ {
+ menu->die();
+ mPopupMenuHandle.markDead();
+ }
llassert(LLMenuGL::sMenuContainer != NULL);
- mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
+ menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
- if (mPopupMenu)
+ if (menu)
{
+ mPopupMenuHandle = menu->getHandle();
if (mIsFriendSignal)
{
bool isFriend = *(*mIsFriendSignal)(uuid);
- LLView* addFriendButton = mPopupMenu->getChild<LLView>("add_friend");
- LLView* removeFriendButton = mPopupMenu->getChild<LLView>("remove_friend");
+ LLView* addFriendButton = menu->getChild<LLView>("add_friend");
+ LLView* removeFriendButton = menu->getChild<LLView>("remove_friend");
if (addFriendButton && removeFriendButton)
{
@@ -2016,8 +2028,8 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
}
}
- mPopupMenu->show(x, y);
- LLMenuGL::showPopup(this, mPopupMenu, x, y);
+ menu->show(x, y);
+ LLMenuGL::showPopup(this, menu, x, y);
return TRUE;
}
}
@@ -3395,3 +3407,42 @@ boost::signals2::connection LLScrollListCtrl::setIsFriendCallback(const is_frien
}
return mIsFriendSignal->connect(cb);
}
+
+bool LLScrollListCtrl::highlightMatchingItems(const std::string& filter_str)
+{
+ if (filter_str == "" || filter_str == " ")
+ {
+ clearHighlightedItems();
+ return false;
+ }
+
+ bool res = false;
+
+ setHighlightedColor(LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red));
+
+ std::string filter_str_lc(filter_str);
+ LLStringUtil::toLower(filter_str_lc);
+
+ std::vector<LLScrollListItem*> data = getAllData();
+ std::vector<LLScrollListItem*>::iterator iter = data.begin();
+ while (iter != data.end())
+ {
+ LLScrollListCell* cell = (*iter)->getColumn(0);
+ if (cell)
+ {
+ std::string value = cell->getValue().asString();
+ LLStringUtil::toLower(value);
+ if (value.find(filter_str_lc) == std::string::npos)
+ {
+ (*iter)->setHighlighted(false);
+ }
+ else
+ {
+ (*iter)->setHighlighted(true);
+ res = true;
+ }
+ }
+ iter++;
+ }
+ return res;
+}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 77d10fdec7..73b4fb036a 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -261,8 +261,8 @@ public:
virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD());
BOOL selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); // FALSE if item not found
- BOOL selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE);
- BOOL selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE);
+ BOOL selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE, S32 column = -1);
+ BOOL selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE, S32 column = -1);
LLScrollListItem* getItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 );
const std::string getSelectedItemLabel(S32 column = 0) const;
LLSD getSelectedValue();
@@ -419,6 +419,8 @@ public:
void setNeedsSort(bool val = true) { mSorted = !val; }
void dirtyColumns(); // some operation has potentially affected column layout or ordering
+ bool highlightMatchingItems(const std::string& filter_str);
+
boost::signals2::connection setSortCallback(sort_signal_t::slot_type cb )
{
if (!mSortCallback) mSortCallback = new sort_signal_t();
@@ -526,7 +528,7 @@ private:
S32 mHighlightedItem;
class LLViewBorder* mBorder;
- LLContextMenu *mPopupMenu;
+ LLHandle<LLContextMenu> mPopupMenuHandle;
LLView *mCommentTextView;
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index ef7c8ec012..c411aafb1a 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -101,7 +101,10 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
// Spin buttons
LLButton::Params up_button_params(p.up_button);
up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height);
- up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
+ // Click callback starts within the button and ends within the button,
+ // but LLSpinCtrl handles the action continuosly so subsribers needs to
+ // be informed about click ending even if outside view, use 'up' instead
+ up_button_params.mouse_up_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
up_button_params.commit_on_capture_lost = true;
@@ -110,7 +113,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
LLButton::Params down_button_params(p.down_button);
down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height);
- down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
+ down_button_params.mouse_up_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
down_button_params.commit_on_capture_lost = true;
mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 0aa7a2d217..8c841540a5 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -1442,6 +1442,11 @@ void LLTabContainer::selectLastTab()
void LLTabContainer::selectNextTab()
{
+ if (mTabList.size() == 0)
+ {
+ return;
+ }
+
BOOL tab_has_focus = FALSE;
if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
{
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 7e4aaa53bf..82a3c01c6d 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -273,6 +273,12 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
LLTextBase::~LLTextBase()
{
mSegments.clear();
+ LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get());
+ if (menu)
+ {
+ menu->die();
+ mPopupMenuHandle.markDead();
+ }
delete mURLClickSignal;
delete mIsFriendSignal;
delete mIsObjectBlockedSignal;
@@ -355,95 +361,113 @@ void LLTextBase::onValueChange(S32 start, S32 end)
{
}
-
-// Draws the black box behind the selected text
-void LLTextBase::drawSelectionBackground()
+std::vector<LLRect> LLTextBase::getSelctionRects()
{
- // Draw selection even if we don't have keyboard focus for search/replace
- if( hasSelection() && !mLineInfoList.empty())
- {
- std::vector<LLRect> selection_rects;
+ // Nor supposed to be called without selection
+ llassert(hasSelection());
+ llassert(!mLineInfoList.empty());
- S32 selection_left = llmin( mSelectionStart, mSelectionEnd );
- S32 selection_right = llmax( mSelectionStart, mSelectionEnd );
+ std::vector<LLRect> selection_rects;
- // Skip through the lines we aren't drawing.
- LLRect content_display_rect = getVisibleDocumentRect();
+ S32 selection_left = llmin(mSelectionStart, mSelectionEnd);
+ S32 selection_right = llmax(mSelectionStart, mSelectionEnd);
- // binary search for line that starts before top of visible buffer
- line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom());
- line_list_t::const_iterator end_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
+ // Skip through the lines we aren't drawing.
+ LLRect content_display_rect = getVisibleDocumentRect();
- bool done = false;
+ // binary search for line that starts before top of visible buffer
+ line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom());
+ line_list_t::const_iterator end_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
- // Find the coordinates of the selected area
- for (;line_iter != end_iter && !done; ++line_iter)
- {
- // is selection visible on this line?
- if (line_iter->mDocIndexEnd > selection_left && line_iter->mDocIndexStart < selection_right)
- {
- segment_set_t::iterator segment_iter;
- S32 segment_offset;
- getSegmentAndOffset(line_iter->mDocIndexStart, &segment_iter, &segment_offset);
-
- LLRect selection_rect;
- selection_rect.mLeft = line_iter->mRect.mLeft;
- selection_rect.mRight = line_iter->mRect.mLeft;
- selection_rect.mBottom = line_iter->mRect.mBottom;
- selection_rect.mTop = line_iter->mRect.mTop;
-
- for(;segment_iter != mSegments.end(); ++segment_iter, segment_offset = 0)
- {
- LLTextSegmentPtr segmentp = *segment_iter;
+ bool done = false;
+
+ // Find the coordinates of the selected area
+ for (; line_iter != end_iter && !done; ++line_iter)
+ {
+ // is selection visible on this line?
+ if (line_iter->mDocIndexEnd > selection_left && line_iter->mDocIndexStart < selection_right)
+ {
+ segment_set_t::iterator segment_iter;
+ S32 segment_offset;
+ getSegmentAndOffset(line_iter->mDocIndexStart, &segment_iter, &segment_offset);
- S32 segment_line_start = segmentp->getStart() + segment_offset;
- S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd);
+ // Use F32 otherwise a string of multiple segments
+ // will accumulate a large error
+ F32 left_precise = line_iter->mRect.mLeft;
+ F32 right_precise = line_iter->mRect.mLeft;
- if (segment_line_start > segment_line_end) break;
+ for (; segment_iter != mSegments.end(); ++segment_iter, segment_offset = 0)
+ {
+ LLTextSegmentPtr segmentp = *segment_iter;
- S32 segment_width = 0;
- S32 segment_height = 0;
+ S32 segment_line_start = segmentp->getStart() + segment_offset;
+ S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd);
- // if selection after beginning of segment
- if(selection_left >= segment_line_start)
- {
- S32 num_chars = llmin(selection_left, segment_line_end) - segment_line_start;
- segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height);
- selection_rect.mLeft += segment_width;
- }
+ if (segment_line_start > segment_line_end) break;
- // if selection_right == segment_line_end then that means we are the first character of the next segment
- // or first character of the next line, in either case we want to add the length of the current segment
- // to the selection rectangle and continue.
- // if selection right > segment_line_end then selection spans end of current segment...
- if (selection_right >= segment_line_end)
- {
- // extend selection slightly beyond end of line
- // to indicate selection of newline character (use "n" character to determine width)
- S32 num_chars = segment_line_end - segment_line_start;
- segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height);
- selection_rect.mRight += segment_width;
- }
- // else if selection ends on current segment...
- else
- {
- S32 num_chars = selection_right - segment_line_start;
- segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height);
- selection_rect.mRight += segment_width;
+ F32 segment_width = 0;
+ S32 segment_height = 0;
- break;
- }
- }
- selection_rects.push_back(selection_rect);
- }
- }
+ // if selection after beginning of segment
+ if (selection_left >= segment_line_start)
+ {
+ S32 num_chars = llmin(selection_left, segment_line_end) - segment_line_start;
+ segmentp->getDimensionsF32(segment_offset, num_chars, segment_width, segment_height);
+ left_precise += segment_width;
+ }
+
+ // if selection_right == segment_line_end then that means we are the first character of the next segment
+ // or first character of the next line, in either case we want to add the length of the current segment
+ // to the selection rectangle and continue.
+ // if selection right > segment_line_end then selection spans end of current segment...
+ if (selection_right >= segment_line_end)
+ {
+ // extend selection slightly beyond end of line
+ // to indicate selection of newline character (use "n" character to determine width)
+ S32 num_chars = segment_line_end - segment_line_start;
+ segmentp->getDimensionsF32(segment_offset, num_chars, segment_width, segment_height);
+ right_precise += segment_width;
+ }
+ // else if selection ends on current segment...
+ else
+ {
+ S32 num_chars = selection_right - segment_line_start;
+ segmentp->getDimensionsF32(segment_offset, num_chars, segment_width, segment_height);
+ right_precise += segment_width;
+
+ break;
+ }
+ }
+
+ LLRect selection_rect;
+ selection_rect.mLeft = left_precise;
+ selection_rect.mRight = right_precise;
+ selection_rect.mBottom = line_iter->mRect.mBottom;
+ selection_rect.mTop = line_iter->mRect.mTop;
+
+ selection_rects.push_back(selection_rect);
+ }
+ }
+
+ return selection_rects;
+}
+
+// Draws the black box behind the selected text
+void LLTextBase::drawSelectionBackground()
+{
+ // Draw selection even if we don't have keyboard focus for search/replace
+ if (hasSelection() && !mLineInfoList.empty())
+ {
+ std::vector<LLRect> selection_rects = getSelctionRects();
// Draw the selection box (we're using a box instead of reversing the colors on the selected text).
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
const LLColor4& color = mSelectedBGColor;
F32 alpha = hasFocus() ? 0.7f : 0.3f;
alpha *= getDrawContext().mAlpha;
+
LLColor4 selection_color(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], alpha);
+ LLRect content_display_rect = getVisibleDocumentRect();
for (std::vector<LLRect>::iterator rect_it = selection_rects.begin();
rect_it != selection_rects.end();
@@ -2551,7 +2575,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
}
S32 pos = getLength();
- S32 start_x = line_iter->mRect.mLeft + doc_rect.mLeft;
+ F32 start_x = line_iter->mRect.mLeft + doc_rect.mLeft;
segment_set_t::iterator line_seg_iter;
S32 line_seg_offset;
@@ -2563,8 +2587,9 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
S32 segment_line_start = segmentp->getStart() + line_seg_offset;
S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd) - segment_line_start;
- S32 text_width, text_height;
- bool newline = segmentp->getDimensions(line_seg_offset, segment_line_length, text_width, text_height);
+ F32 text_width;
+ S32 text_height;
+ bool newline = segmentp->getDimensionsF32(line_seg_offset, segment_line_length, text_width, text_height);
if(newline)
{
@@ -2584,8 +2609,9 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
S32 offset;
if (!segmentp->canEdit())
{
- S32 segment_width, segment_height;
- segmentp->getDimensions(0, segmentp->getEnd() - segmentp->getStart(), segment_width, segment_height);
+ F32 segment_width;
+ S32 segment_height;
+ segmentp->getDimensionsF32(0, segmentp->getEnd() - segmentp->getStart(), segment_width, segment_height);
if (round && local_x - start_x > segment_width / 2)
{
offset = segment_line_length;
@@ -2632,17 +2658,11 @@ LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const
return LLRect();
}
- LLRect doc_rect;
-
// clamp pos to valid values
pos = llclamp(pos, 0, mLineInfoList.back().mDocIndexEnd - 1);
line_list_t::const_iterator line_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), pos, line_end_compare());
- doc_rect.mLeft = line_iter->mRect.mLeft;
- doc_rect.mBottom = line_iter->mRect.mBottom;
- doc_rect.mTop = line_iter->mRect.mTop;
-
segment_set_t::iterator line_seg_iter;
S32 line_seg_offset;
segment_set_t::iterator cursor_seg_iter;
@@ -2650,6 +2670,8 @@ LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const
getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset);
getSegmentAndOffset(pos, &cursor_seg_iter, &cursor_seg_offset);
+ F32 doc_left_precise = line_iter->mRect.mLeft;
+
while(line_seg_iter != mSegments.end())
{
const LLTextSegmentPtr segmentp = *line_seg_iter;
@@ -2657,18 +2679,20 @@ LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const
if (line_seg_iter == cursor_seg_iter)
{
// cursor advanced to right based on difference in offset of cursor to start of line
- S32 segment_width, segment_height;
- segmentp->getDimensions(line_seg_offset, cursor_seg_offset - line_seg_offset, segment_width, segment_height);
- doc_rect.mLeft += segment_width;
+ F32 segment_width;
+ S32 segment_height;
+ segmentp->getDimensionsF32(line_seg_offset, cursor_seg_offset - line_seg_offset, segment_width, segment_height);
+ doc_left_precise += segment_width;
break;
}
else
{
// add remainder of current text segment to cursor position
- S32 segment_width, segment_height;
- segmentp->getDimensions(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset, segment_width, segment_height);
- doc_rect.mLeft += segment_width;
+ F32 segment_width;
+ S32 segment_height;
+ segmentp->getDimensionsF32(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset, segment_width, segment_height);
+ doc_left_precise += segment_width;
// offset will be 0 for all segments after the first
line_seg_offset = 0;
// go to next text segment on this line
@@ -2676,6 +2700,11 @@ LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const
}
}
+ LLRect doc_rect;
+ doc_rect.mLeft = doc_left_precise;
+ doc_rect.mBottom = line_iter->mRect.mBottom;
+ doc_rect.mTop = line_iter->mRect.mTop;
+
// set rect to 0 width
doc_rect.mRight = doc_rect.mLeft;
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 25f8fa1c2b..e3cf56a5ee 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -638,6 +638,8 @@ protected:
return mLabel.getString() + getToolTip();
}
+ std::vector<LLRect> getSelctionRects();
+
protected:
// text segmentation and flow
segment_set_t mSegments;
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index b1f8b00cab..3d2a426913 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -257,7 +257,6 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mMouseDownY(0),
mTabsToNextField(p.ignore_tab),
mPrevalidateFunc(p.prevalidate_callback()),
- mContextMenu(NULL),
mShowContextMenu(p.show_context_menu),
mEnableTooltipPaste(p.enable_tooltip_paste),
mPassDelete(FALSE),
@@ -301,8 +300,13 @@ LLTextEditor::~LLTextEditor()
// Scrollbar is deleted by LLView
std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer());
mUndoStack.clear();
- // context menu is owned by menu holder, not us
- //delete mContextMenu;
+ // Mark the menu as dead or its retained in memory till shutdown.
+ LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get());
+ if(menu)
+ {
+ menu->die();
+ mContextMenuHandle.markDead();
+ }
}
////////////////////////////////////////////////////////////
@@ -2051,12 +2055,19 @@ void LLTextEditor::setEnabled(BOOL enabled)
void LLTextEditor::showContextMenu(S32 x, S32 y)
{
- if (!mContextMenu)
+ LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get());
+ if (!menu)
{
llassert(LLMenuGL::sMenuContainer != NULL);
- mContextMenu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_text_editor.xml",
+ menu = LLUICtrlFactory::createFromFile<LLContextMenu>("menu_text_editor.xml",
LLMenuGL::sMenuContainer,
LLMenuHolderGL::child_registry_t::instance());
+ if(!menu)
+ {
+ LL_WARNS() << "Failed to create menu for LLTextEditor: " << getName() << LL_ENDL;
+ return;
+ }
+ mContextMenuHandle = menu->getHandle();
}
// Route menu to this class
@@ -2102,11 +2113,11 @@ void LLTextEditor::showContextMenu(S32 x, S32 y)
}
}
- mContextMenu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty()));
- mContextMenu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled));
- mContextMenu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled));
- mContextMenu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled));
- mContextMenu->show(screen_x, screen_y, this);
+ menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty()));
+ menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled));
+ menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled));
+ menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled));
+ menu->show(screen_x, screen_y, this);
}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 1a10d2fd1e..f3939248c2 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -329,7 +329,7 @@ private:
keystroke_signal_t mKeystrokeSignal;
LLTextValidate::validate_func_t mPrevalidateFunc;
- LLContextMenu* mContextMenu;
+ LLHandle<LLContextMenu> mContextMenuHandle;
}; // end class LLTextEditor
// Build time optimization, generate once in .cpp file
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index 5150df25f2..2707f7a15c 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -127,7 +127,12 @@ LLToolBar::LLToolBar(const LLToolBar::Params& p)
LLToolBar::~LLToolBar()
{
- delete mPopupMenuHandle.get();
+ auto menu = mPopupMenuHandle.get();
+ if (menu)
+ {
+ menu->die();
+ mPopupMenuHandle.markDead();
+ }
delete mButtonAddSignal;
delete mButtonEnterSignal;
delete mButtonLeaveSignal;