diff options
Diffstat (limited to 'indra/llui')
| -rw-r--r-- | indra/llui/llchat.h | 3 | ||||
| -rw-r--r-- | indra/llui/llcheckboxctrl.cpp | 6 | ||||
| -rw-r--r-- | indra/llui/llflatlistview.cpp | 11 | ||||
| -rw-r--r-- | indra/llui/llflatlistview.h | 1 | ||||
| -rw-r--r-- | indra/llui/llfolderview.cpp | 74 | ||||
| -rw-r--r-- | indra/llui/llfolderview.h | 8 | ||||
| -rw-r--r-- | indra/llui/llfolderviewitem.cpp | 82 | ||||
| -rw-r--r-- | indra/llui/llfolderviewmodel.h | 18 | ||||
| -rw-r--r-- | indra/llui/lllineeditor.cpp | 18 | ||||
| -rw-r--r-- | indra/llui/llmenugl.cpp | 58 | ||||
| -rw-r--r-- | indra/llui/llmenugl.h | 3 | ||||
| -rw-r--r-- | indra/llui/llmultislider.cpp | 2 | ||||
| -rw-r--r-- | indra/llui/llscrolllistctrl.cpp | 77 | ||||
| -rw-r--r-- | indra/llui/llscrolllistctrl.h | 8 | ||||
| -rw-r--r-- | indra/llui/llspinctrl.cpp | 7 | ||||
| -rw-r--r-- | indra/llui/lltabcontainer.cpp | 5 | ||||
| -rw-r--r-- | indra/llui/lltextbase.cpp | 203 | ||||
| -rw-r--r-- | indra/llui/lltextbase.h | 2 | ||||
| -rw-r--r-- | indra/llui/lltexteditor.cpp | 31 | ||||
| -rw-r--r-- | indra/llui/lltexteditor.h | 2 | ||||
| -rw-r--r-- | indra/llui/lltoolbar.cpp | 7 | ||||
| -rw-r--r-- | indra/llui/lltooltip.cpp | 36 | ||||
| -rw-r--r-- | indra/llui/lltooltip.h | 12 | ||||
| -rw-r--r-- | indra/llui/llview.cpp | 20 | ||||
| -rw-r--r-- | indra/llui/llview.h | 1 | 
25 files changed, 484 insertions, 211 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..5170816671 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(); @@ -1506,6 +1532,22 @@ BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask )  	return LLView::handleHover( x, y, mask );  } +LLFolderViewItem* LLFolderView::getHoveredItem() const +{ +	return dynamic_cast<LLFolderViewItem*>(mHoveredItem.get()); +} + +void LLFolderView::setHoveredItem(LLFolderViewItem* itemp) +{ +	if (mHoveredItem.get() != itemp) +	{ +		if (itemp) +			mHoveredItem = itemp->getHandle(); +		else +			mHoveredItem.markDead(); +	} +} +  BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  									 EDragAndDropType cargo_type,  									 void* cargo_data,  @@ -1531,7 +1573,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..237239c5d1 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -144,6 +144,10 @@ public:  	// applies filters to control visibility of items  	virtual void filter( LLFolderViewFilter& filter); +	void              clearHoveredItem() { setHoveredItem(nullptr); } +	LLFolderViewItem* getHoveredItem() const; +	void              setHoveredItem(LLFolderViewItem* itemp); +  	// Get the last selected item  	virtual LLFolderViewItem* getCurSelectedItem( void );      selected_items_t& getSelectedItems( void ); @@ -235,6 +239,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,7 +277,9 @@ protected:  protected:  	LLHandle<LLView>					mPopupMenuHandle; +	std::string						mMenuFileName; +	LLHandle<LLView>				mHoveredItem;  	selected_items_t				mSelectedItems;  	bool							mKeyboardSelection,  									mAllowMultiSelect, @@ -327,6 +334,7 @@ protected:  	LLFolderViewItem*				mDraggingOverItem; // See EXT-719  	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar; +	LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;  public:  	static F32 sAutoOpenTime; diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index eba93beed9..115cfcf3a0 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -162,7 +162,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)  		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("InventoryItemColor", DEFAULT_WHITE); +		sSuffixColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);  		sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);  		sColorSetInitialized = true;  	} @@ -395,7 +395,7 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height )              // it is purely visual, so it is fine to do at our laisure              refreshSuffix();          } -		mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight;  +		mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(LLFontGL::NORMAL)->getWidth(mLabelSuffix) + mLabelPaddingRight;   		mLabelWidthDirty = false;  	} @@ -624,11 +624,14 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )  			getWindow()->setCursor(UI_CURSOR_NOLOCKED);  		} +		root->clearHoveredItem();  		return TRUE;  	}  	else  	{ -		getRoot()->setShowSelectionContext(FALSE); +		LLFolderView* pRoot = getRoot(); +		pRoot->setHoveredItem(this); +		pRoot->setShowSelectionContext(FALSE);  		getWindow()->setCursor(UI_CURSOR_ARROW);  		// let parent handle this then...  		return FALSE; @@ -683,6 +686,13 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask )  void LLFolderViewItem::onMouseLeave(S32 x, S32 y, MASK mask)  {  	mIsMouseOverTitle = false; + +	// NOTE: LLViewerWindow::updateUI() calls "enter" before "leave"; if the mouse moved to another item, we can't just outright clear it +	LLFolderView* pRoot = getRoot(); +	if (this == pRoot->getHoveredItem()) +	{ +		pRoot->clearHoveredItem(); +	}  }  BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, @@ -925,16 +935,43 @@ void LLFolderViewItem::draw()  	F32 text_left = (F32)getLabelXPos();  	std::string combined_string = mLabel + mLabelSuffix; +    const LLFontGL* suffix_font = getLabelFontForStyle(LLFontGL::NORMAL); +    S32 filter_offset = mViewModelItem->getFilterStringOffset();  	if (filter_string_length > 0)  	{ -		S32 left = ll_round(text_left) + font->getWidth(combined_string, 0, mViewModelItem->getFilterStringOffset()) - 2; +        S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD); +        S32 top = getRect().getHeight() - TOP_PAD; +        if(mLabelSuffix.empty() || (font == suffix_font)) +        { +        S32 left = ll_round(text_left) + font->getWidth(combined_string, 0, mViewModelItem->getFilterStringOffset()) - 2;  		S32 right = left + font->getWidth(combined_string, mViewModelItem->getFilterStringOffset(), filter_string_length) + 2; -		S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD); -		S32 top = getRect().getHeight() - TOP_PAD;  		LLUIImage* box_image = default_params.selection_image;  		LLRect box_rect(left, top, right, bottom);  		box_image->draw(box_rect, sFilterBGColor); +        } +        else +        { +            S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length); +            if(label_filter_length > 0) +            { +                S32 left = ll_round(text_left) + font->getWidthF32(mLabel, 0, llmin(filter_offset, (S32)mLabel.size())) - 2; +                S32 right = left + font->getWidthF32(mLabel, filter_offset, label_filter_length) + 2; +                LLUIImage* box_image = default_params.selection_image; +                LLRect box_rect(left, top, right, bottom); +                box_image->draw(box_rect, sFilterBGColor); +            } +            S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length; +            if(suffix_filter_length > 0) +            { +                S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size()); +                S32 left = ll_round(text_left) + font->getWidthF32(mLabel, 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix, 0, suffix_offset) - 2; +                S32 right = left + suffix_font->getWidthF32(mLabelSuffix, suffix_offset, suffix_filter_length) + 2; +                LLUIImage* box_image = default_params.selection_image; +                LLRect box_rect(left, top, right, bottom); +                box_image->draw(box_rect, sFilterBGColor); +            } +        }      }      LLColor4 color = (mIsSelected && filled) ? mFontHighlightColor : mFontColor; @@ -951,7 +988,7 @@ void LLFolderViewItem::draw()  	//  	if (!mLabelSuffix.empty())  	{ -		font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor, +        suffix_font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,  						  LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,  						  S32_MAX, S32_MAX, &right_x, FALSE );  	} @@ -961,12 +998,35 @@ void LLFolderViewItem::draw()  	//      if (filter_string_length > 0)      { -        S32 filter_offset = mViewModelItem->getFilterStringOffset(); -        F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length); -        F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; -        font->renderUTF8( combined_string, filter_offset, match_string_left, yy, +        if(mLabelSuffix.empty() || (font == suffix_font)) +        { +            F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length); +            F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; +            font->renderUTF8( combined_string, filter_offset, match_string_left, yy,              sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,              filter_string_length, S32_MAX, &right_x, FALSE ); +        } +        else +        { +            S32 label_filter_length = llmin((S32)mLabel.size() - filter_offset, (S32)filter_string_length); +            if(label_filter_length > 0) +            { +                F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel, filter_offset, label_filter_length); +                F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; +                font->renderUTF8( mLabel, filter_offset, match_string_left, yy, + sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x, FALSE ); +            } +             +            S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length; +            if(suffix_filter_length > 0) +            { +                S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size()); +                F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix, 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix, suffix_offset, suffix_filter_length); +                F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; +                suffix_font->renderUTF8( mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, suffix_filter_length, S32_MAX, &right_x, FALSE ); +            } +        } +      }      //Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to 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() , ¢er_x, ¢er_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(), ¢er_x, ¢er_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; diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 2f56a8b1d0..a6552d4ff1 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -163,6 +163,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)  :	LLPanel(p),  	mHasClickCallback(p.click_callback.isProvided()),  	mPadding(p.padding), +	mMaxWidth(p.max_width),  	mTextBox(NULL),  	mInfoButton(NULL),  	mPlayMediaButton(NULL), @@ -272,7 +273,7 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)  	// do this *after* we've had our size set in LLPanel::initFromParams();  	const S32 REALLY_LARGE_HEIGHT = 10000; -	mTextBox->reshape(p.max_width, REALLY_LARGE_HEIGHT); +	mTextBox->reshape(mMaxWidth, REALLY_LARGE_HEIGHT);  	if (p.styled_message.isProvided())  	{ @@ -288,16 +289,19 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)  		mTextBox->setText(p.message());  	} -	S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth() + 1); +	updateTextBox(); +	snapToChildren(); +} + +void LLToolTip::updateTextBox() +{ +	S32 text_width = llmin(mMaxWidth, mTextBox->getTextPixelWidth() + 1);  	S32 text_height = mTextBox->getTextPixelHeight();  	mTextBox->reshape(text_width, text_height); -	if (mInfoButton) -	{ -		LLRect text_rect = mTextBox->getRect(); -		LLRect icon_rect = mInfoButton->getRect(); -		mTextBox->translate(0, icon_rect.getCenterY() - text_rect.getCenterY()); -	} - +} +  +void LLToolTip::snapToChildren() +{  	// reshape tooltip panel to fit text box  	LLRect tooltip_rect = calcBoundingRect();  	tooltip_rect.mTop += mPadding; @@ -305,7 +309,14 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)  	tooltip_rect.mBottom = 0;  	tooltip_rect.mLeft = 0; -	mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding)); +	if (mInfoButton) +	{ +		mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding)); + +		LLRect text_rect = mTextBox->getRect(); +		LLRect icon_rect = mInfoButton->getRect(); +		mInfoButton->translate(0, text_rect.getCenterY() - icon_rect.getCenterY()); +	}  	setShape(tooltip_rect);  } @@ -428,7 +439,10 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)  	}  	tooltip_params.rect = LLRect (0, 1, 1, 0); -	mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params); +	if (tooltip_params.create_callback.isProvided()) +		mToolTip = tooltip_params.create_callback()(tooltip_params); +	else +		mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);  	gToolTipView->addChild(mToolTip); diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h index 0b1fbe5367..86943625ff 100644 --- a/indra/llui/lltooltip.h +++ b/indra/llui/lltooltip.h @@ -68,6 +68,7 @@ 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;  		Optional<std::string>		message;  		Multiple<StyledText>		styled_message; @@ -84,6 +85,8 @@ public:  		Optional<bool>				time_based_media,  									web_based_media,  									media_playing; +		Optional<create_callback_t>	create_callback; +		Optional<LLSD>				create_params;  		Optional<click_callback_t>	click_callback,  									click_playmedia_callback,  									click_homepage_callback; @@ -103,11 +106,15 @@ public:  	bool hasClickCallback();  	LLToolTip(const Params& p); -	void initFromParams(const LLToolTip::Params& params); +	virtual void initFromParams(const LLToolTip::Params& params);  	void getToolTipMessage(std::string & message); -private: +protected: +	void updateTextBox(); +	void snapToChildren(); + +protected:  	class LLTextBox*	mTextBox;  	class LLButton*     mInfoButton;  	class LLButton*     mPlayMediaButton; @@ -117,6 +124,7 @@ private:  	LLFrameTimer	mVisibleTimer;  	bool			mHasClickCallback;  	S32				mPadding;	// pixels +	S32				mMaxWidth;  };  // used for the inspector tooltips which need different background images etc. diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 9ba71913d0..10e4755cd3 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -877,6 +877,17 @@ LLView*	LLView::childFromPoint(S32 x, S32 y, bool recur)  	return 0;  } +F32 LLView::getTooltipTimeout() +{ +    static LLCachedControl<F32> tooltip_fast_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFastDelay", 0.1f); +    static LLCachedControl<F32> tooltip_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipDelay", 0.7f); +    // allow "scrubbing" over ui by showing next tooltip immediately +    // if previous one was still visible +    return (F32)(LLToolTipMgr::instance().toolTipVisible() +    ? tooltip_fast_delay +    : tooltip_delay); +} +  BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)  {  	BOOL handled = FALSE; @@ -886,14 +897,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)  	std::string tooltip = getToolTip();  	if (!tooltip.empty())  	{ -        static LLCachedControl<F32> tooltip_fast_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFastDelay", 0.1f); -        static LLCachedControl<F32> tooltip_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipDelay", 0.7f);          static LLCachedControl<bool> allow_ui_tooltips(*LLUI::getInstance()->mSettingGroups["config"], "BasicUITooltips", true); -		// allow "scrubbing" over ui by showing next tooltip immediately -		// if previous one was still visible -		F32 timeout = LLToolTipMgr::instance().toolTipVisible()  -		              ? tooltip_fast_delay -		              : tooltip_delay;  		// Even if we don't show tooltips, consume the event, nothing below should show tooltip  		if (allow_ui_tooltips) @@ -901,7 +905,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)  			LLToolTipMgr::instance().show(LLToolTip::Params()  			                              .message(tooltip)  			                              .sticky_rect(calcScreenRect()) -			                              .delay_time(timeout)); +			                              .delay_time(getTooltipTimeout()));  		}  		handled = TRUE;  	} diff --git a/indra/llui/llview.h b/indra/llui/llview.h index bec45df78a..444a4c3cb5 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -243,6 +243,7 @@ public:  	ECursorType	getHoverCursor() { return mHoverCursor; } +    static F32 getTooltipTimeout();  	virtual const std::string getToolTip() const			{ return mToolTipMsg.getString(); }  	void		sendChildToFront(LLView* child); | 
