diff options
| author | Oz Linden <oz@lindenlab.com> | 2010-11-08 16:47:46 -0500 | 
|---|---|---|
| committer | Oz Linden <oz@lindenlab.com> | 2010-11-08 16:47:46 -0500 | 
| commit | b657516f72f016a918e0ff627105dd380a94394c (patch) | |
| tree | 7d30ace2d3cba42c5f7de1c3dd23748e31b2803f /indra/llui | |
| parent | 451d115c1009ded2b2d74efefbe0611c62343eed (diff) | |
| parent | c446062bd3bd3f172b20f22f2086cea962fb7278 (diff) | |
pull beta changes back to development
Diffstat (limited to 'indra/llui')
| -rw-r--r-- | indra/llui/llaccordionctrltab.cpp | 55 | ||||
| -rw-r--r-- | indra/llui/llmenubutton.cpp | 144 | ||||
| -rw-r--r-- | indra/llui/llmenubutton.h | 33 | ||||
| -rw-r--r-- | indra/llui/llmenugl.cpp | 205 | ||||
| -rw-r--r-- | indra/llui/llmenugl.h | 12 | ||||
| -rw-r--r-- | indra/llui/llpanel.cpp | 2 | ||||
| -rw-r--r-- | indra/llui/lltextbase.cpp | 36 | ||||
| -rw-r--r-- | indra/llui/lltoggleablemenu.cpp | 18 | ||||
| -rw-r--r-- | indra/llui/lltoggleablemenu.h | 5 | ||||
| -rw-r--r-- | indra/llui/lluistring.h | 10 | ||||
| -rw-r--r-- | indra/llui/llurlentry.cpp | 5 | 
11 files changed, 357 insertions, 168 deletions
| diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 179b32098a..9d49c1a831 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -456,8 +456,7 @@ BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)  	{  		if(y >= (getRect().getHeight() - HEADER_HEIGHT) )  		{ -			LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); -			header->setFocus(true); +			mHeader->setFocus(true);  			changeOpenClose(getDisplayChildren());  			//reset stored state @@ -509,10 +508,9 @@ void LLAccordionCtrlTab::setAccordionView(LLView* panel)  std::string LLAccordionCtrlTab::getTitle() const  { -	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); -	if (header) +	if (mHeader)  	{ -		return header->getTitle(); +		return mHeader->getTitle();  	}  	else  	{ @@ -522,57 +520,51 @@ std::string LLAccordionCtrlTab::getTitle() const  void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl)  { -	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); -	if (header) +	if (mHeader)  	{ -		header->setTitle(title, hl); +		mHeader->setTitle(title, hl);  	}  }  void LLAccordionCtrlTab::setTitleFontStyle(std::string style)  { -	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); -	if (header) +	if (mHeader)  	{ -		header->setTitleFontStyle(style); +		mHeader->setTitleFontStyle(style);  	}  }  void LLAccordionCtrlTab::setTitleColor(LLUIColor color)  { -	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); -	if (header) +	if (mHeader)  	{ -		header->setTitleColor(color); +		mHeader->setTitleColor(color);  	}  }  boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)  { -	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); -	if (header) +	if (mHeader)  	{ -		return header->setFocusReceivedCallback(cb); +		return mHeader->setFocusReceivedCallback(cb);  	}  	return boost::signals2::connection();  }  boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb)  { -	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); -	if (header) +	if (mHeader)  	{ -		return header->setFocusLostCallback(cb); +		return mHeader->setFocusLostCallback(cb);  	}  	return boost::signals2::connection();  }  void LLAccordionCtrlTab::setSelected(bool is_selected)  { -	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME); -	if (header) +	if (mHeader)  	{ -		header->setSelected(is_selected); +		mHeader->setSelected(is_selected);  	}  } @@ -776,8 +768,7 @@ S32 LLAccordionCtrlTab::notify(const LLSD& info)  BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)  { -	LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);	 -	if( !header->hasFocus() ) +	if( !mHeader->hasFocus() )  		return LLUICtrl::handleKey(key, mask, called_from_parent);  	if ( (key == KEY_RETURN )&& mask == MASK_NONE) @@ -830,15 +821,19 @@ BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)  void LLAccordionCtrlTab::showAndFocusHeader()  { -	LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);	 -	header->setFocus(true); -	header->setSelected(mSelectionEnabled); +	mHeader->setFocus(true); +	mHeader->setSelected(mSelectionEnabled);  	LLRect screen_rc; -	LLRect selected_rc = header->getRect(); +	LLRect selected_rc = mHeader->getRect();  	localRectToScreen(selected_rc, &screen_rc); -	notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue())); +	// This call to notifyParent() is intended to deliver "scrollToShowRect" command +	// to the parent LLAccordionCtrl so by calling it from the direct parent of this +	// accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain +	// is shortened and messages from inside the collapsed tabs are avoided. +	// See STORM-536. +	getParent()->notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));  }  void    LLAccordionCtrlTab::storeOpenCloseState()  { diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 3df05f4d3f..ac568a83e4 100644 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -29,7 +29,7 @@  #include "llmenubutton.h"  // Linden library includes -#include "llmenugl.h" +#include "lltoggleablemenu.h"  #include "llstring.h"  #include "v4color.h" @@ -44,58 +44,77 @@ LLMenuButton::Params::Params()  LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)  :	LLButton(p), -	mMenu(NULL), -	mMenuVisibleLastFrame(false) +	mIsMenuShown(false), +	mMenuPosition(MP_BOTTOM_LEFT)  {  	std::string menu_filename = p.menu_filename;  	if (!menu_filename.empty())  	{ -		mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); -		if (!mMenu) +		LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); +		if (!menu)  		{  			llwarns << "Error loading menu_button menu" << llendl; +			return;  		} + +		menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2)); + +		mMenuHandle = menu->getHandle(); + +		updateMenuOrigin();  	}  } -void LLMenuButton::toggleMenu() +boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )  { -    if(!mMenu) -		return; +	return LLUICtrl::setMouseDownCallback(cb); +} -	if (mMenu->getVisible() || mMenuVisibleLastFrame) -	{ -		mMenu->setVisible(FALSE); -	} -	else +void LLMenuButton::hideMenu() +{ +	if(mMenuHandle.isDead()) return; + +	LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get()); +	if (menu)  	{ -	    LLRect rect = getRect(); -		//mMenu->needsArrange(); //so it recalculates the visible elements -		LLMenuGL::showPopup(getParent(), mMenu, rect.mLeft, rect.mBottom); +		menu->setVisible(FALSE);  	}  } - -void LLMenuButton::hideMenu()  -{  -	if(!mMenu) -		return; -	mMenu->setVisible(FALSE);  +LLToggleableMenu* LLMenuButton::getMenu() +{ +	return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());  } +void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/) +{ +	if (!menu) return; + +	mMenuHandle = menu->getHandle(); +	mMenuPosition = position; + +	menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2)); +}  BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )  { +	if (mMenuHandle.isDead()) return FALSE; +  	if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))  	{ +		// *HACK: We emit the mouse down signal to fire the callback bound to the +		// menu emerging event before actually displaying the menu. See STORM-263. +		LLUICtrl::handleMouseDown(-1, -1, MASK_NONE); +  		toggleMenu();  		return TRUE;  	} -	if (mMenu && mMenu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE) +	LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get()); +	if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)  	{ -		mMenu->setVisible(FALSE); +		menu->setVisible(FALSE);  		return TRUE;  	} @@ -104,34 +123,77 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )  BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)  { -	if (hasTabStop() && !getIsChrome()) -	{ -		setFocus(TRUE); -	} +	LLButton::handleMouseDown(x, y, mask);  	toggleMenu(); -	if (getSoundFlags() & MOUSE_DOWN) -	{ -		make_ui_sound("UISndClick"); -	} -  	return TRUE;  } -void LLMenuButton::draw() +void LLMenuButton::toggleMenu()  { -	//we save this off so next frame when we try to close it by  -	//button click, and it hides menus before we get to it, we know -	mMenuVisibleLastFrame = mMenu && mMenu->getVisible(); -	 -	if (mMenuVisibleLastFrame) +	if(mMenuHandle.isDead()) return; + +	LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get()); +	if (!menu) return; + +	// Store the button rectangle to toggle menu visibility if a mouse event +	// occurred inside or outside the button rect. +	menu->setButtonRect(this); + +	if (!menu->toggleVisibility() && mIsMenuShown) +	{ +		setForcePressedState(false); +		mIsMenuShown = false; +	} +	else  	{ +		menu->buildDrawLabels(); +		menu->arrangeAndClear(); +		menu->updateParent(LLMenuGL::sMenuContainer); + +		updateMenuOrigin(); + +		LLMenuGL::showPopup(getParent(), menu, mX, mY); +  		setForcePressedState(true); +		mIsMenuShown = true;  	} +} + +void LLMenuButton::updateMenuOrigin() +{ +	if (mMenuHandle.isDead()) return; -	LLButton::draw(); +	LLRect rect = getRect(); -	setForcePressedState(false); +	switch (mMenuPosition) +	{ +		case MP_TOP_LEFT: +		{ +			mX = rect.mLeft; +			mY = rect.mTop + mMenuHandle.get()->getRect().getHeight(); +			break; +		} +		case MP_BOTTOM_LEFT: +		{ +			mX = rect.mLeft; +			mY = rect.mBottom; +			break; +		} +	}  } +void LLMenuButton::onMenuVisibilityChange(const LLSD& param) +{ +	bool new_visibility = param["visibility"].asBoolean(); +	bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean(); + +	// Reset the button "pressed" state only if the menu is shown by this particular +	// menu button (not any other control) and is not being closed by a click on the button. +	if (!new_visibility && !is_closed_by_button_click && mIsMenuShown) +	{ +		setForcePressedState(false); +		mIsMenuShown = false; +	} +} diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index 81ca0e047c..9e91b9e99d 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -29,7 +29,7 @@  #include "llbutton.h" -class LLMenuGL; +class LLToggleableMenu;  class LLMenuButton  : public LLButton @@ -42,22 +42,41 @@ public:  		Optional<std::string>	menu_filename;  		Params(); -	};	 +	}; + +	typedef enum e_menu_position +	{ +		MP_TOP_LEFT, +		MP_BOTTOM_LEFT +	} EMenuPosition; -	void toggleMenu(); -	/*virtual*/ void draw(); +	boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); +  	/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);  	/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); +  	void hideMenu(); -	LLMenuGL* getMenu() { return mMenu; } + +	LLToggleableMenu* getMenu(); +	void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT); + +	void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }  protected:  	friend class LLUICtrlFactory;  	LLMenuButton(const Params&); +	void toggleMenu(); +	void updateMenuOrigin(); + +	void onMenuVisibilityChange(const LLSD& param); +  private: -	LLMenuGL*	mMenu; -	bool mMenuVisibleLastFrame; +	LLHandle<LLView>		mMenuHandle; +	bool					mIsMenuShown; +	EMenuPosition			mMenuPosition; +	S32						mX; +	S32						mY;  }; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 6d590cf54e..a6cf86d9b8 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1848,89 +1848,104 @@ BOOL LLMenuGL::isOpen()  	}  } -void LLMenuGL::scrollItemsUp() + + +bool LLMenuGL::scrollItems(EScrollingDirection direction)  { -	// Slowing down the items scrolling when arrow button is held  +	// Slowing down items scrolling when arrow button is held  	if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem)  	{  		mScrollItemsTimer.setTimerExpirySec(.033f);  	}  	else  	{ -		return; +		return false;  	} -	item_list_t::iterator cur_item_iter; -	item_list_t::iterator prev_item_iter; -	for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) +	switch (direction)  	{ -		if( (*cur_item_iter) == mFirstVisibleItem) +	case SD_UP: +	{ +		item_list_t::iterator cur_item_iter; +		item_list_t::iterator prev_item_iter; +		for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)  		{ -			break; +			if( (*cur_item_iter) == mFirstVisibleItem) +			{ +				break; +			} +			if ((*cur_item_iter)->getVisible()) +			{ +				prev_item_iter = cur_item_iter; +			}  		} -		if ((*cur_item_iter)->getVisible()) + +		if ((*prev_item_iter)->getVisible())  		{ -			prev_item_iter = cur_item_iter; +			mFirstVisibleItem = *prev_item_iter;  		} +		break;  	} - -	if ((*prev_item_iter)->getVisible()) -	{ -		mFirstVisibleItem = *prev_item_iter; -	} -	 -	mNeedsArrange = TRUE; -	arrangeAndClear(); -} - -void LLMenuGL::scrollItemsDown() -{ -	// Slowing down the items scrolling when arrow button is held  -	if (mScrollItemsTimer.hasExpired()) -	{ -		mScrollItemsTimer.setTimerExpirySec(.033f); -	} -	else -	{ -		return; -	} -	 -	if (NULL == mFirstVisibleItem) -	{ -		mFirstVisibleItem = *mItems.begin(); -	} - -	item_list_t::iterator cur_item_iter; -	 -	for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) +	case SD_DOWN:  	{ -		if( (*cur_item_iter) == mFirstVisibleItem) +		if (NULL == mFirstVisibleItem)  		{ -			break; +			mFirstVisibleItem = *mItems.begin();  		} -	} -	item_list_t::iterator next_item_iter; +		item_list_t::iterator cur_item_iter; -	if (cur_item_iter != mItems.end()) -	{ -		for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++) +		for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)  		{ -			if( (*next_item_iter)->getVisible()) +			if( (*cur_item_iter) == mFirstVisibleItem)  			{  				break;  			}  		} -		 -		if (next_item_iter != mItems.end() && -		    (*next_item_iter)->getVisible()) + +		item_list_t::iterator next_item_iter; + +		if (cur_item_iter != mItems.end())  		{ -			mFirstVisibleItem = *next_item_iter; +			for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++) +			{ +				if( (*next_item_iter)->getVisible()) +				{ +					break; +				} +			} + +			if (next_item_iter != mItems.end() && +				(*next_item_iter)->getVisible()) +			{ +				mFirstVisibleItem = *next_item_iter; +			}  		} +		break;  	} -	 +	case SD_BEGIN: +	{ +		mFirstVisibleItem = *mItems.begin(); +		break; +	} +	case SD_END: +	{ +		item_list_t::reverse_iterator first_visible_item_iter = mItems.rend(); + +		// Advance by mMaxScrollableItems back from the end of the list +		// to make the last item visible. +		std::advance(first_visible_item_iter, mMaxScrollableItems); +		mFirstVisibleItem = *first_visible_item_iter; +		break; +	} +	default: +		llwarns << "Unknown scrolling direction: " << direction << llendl; +	} +  	mNeedsArrange = TRUE;  	arrangeAndClear(); + +	return true;  }  // rearrange the child rects so they fit the shape of the menu. @@ -2162,7 +2177,7 @@ void LLMenuGL::arrange( void )  					LLMenuScrollItem::Params item_params;  					item_params.name(ARROW_UP);  					item_params.arrow_type(LLMenuScrollItem::ARROW_UP); -					item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsUp, this)); +					item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP));  					mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);  					LLUICtrl::addChild(mArrowUpItem); @@ -2173,7 +2188,7 @@ void LLMenuGL::arrange( void )  					LLMenuScrollItem::Params item_params;  					item_params.name(ARROW_DOWN);  					item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN); -					item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsDown, this)); +					item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN));  					mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);  					LLUICtrl::addChild(mArrowDownItem);				 @@ -2603,14 +2618,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa  		((LLFloater*)getParent())->setFocus(TRUE);  	} -	item_list_t::iterator cur_item_iter; -	for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); ++cur_item_iter) -	{ -		if( (*cur_item_iter) == cur_item) -		{ -			break; -		} -	} +	// Current item position in the items list +	item_list_t::iterator cur_item_iter = std::find(mItems.begin(), mItems.end(), cur_item);  	item_list_t::iterator next_item_iter;  	if (cur_item_iter == mItems.end()) @@ -2621,9 +2630,37 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa  	{  		next_item_iter = cur_item_iter;  		next_item_iter++; + +		// First visible item position in the items list +		item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem); +  		if (next_item_iter == mItems.end())  		{  			next_item_iter = mItems.begin(); + +			// If current item is the last in the list, the menu is scrolled to the beginning +			// and the first item is highlighted. +			if (mScrollable && !scrollItems(SD_BEGIN)) +			{ +				return NULL; +			} +		} +		// If current item is the last visible, the menu is scrolled one item down +		// and the next item is highlighted. +		else if (mScrollable && +				 (U32)std::abs(std::distance(first_visible_item_iter, next_item_iter)) >= mMaxScrollableItems) +		{ +			// Call highlightNextItem() recursively only if the menu was successfully scrolled down. +			// If scroll timer hasn't expired yet the menu won't be scrolled and calling +			// highlightNextItem() will result in an endless recursion. +			if (scrollItems(SD_DOWN)) +			{ +				return highlightNextItem(cur_item, skip_disabled); +			} +			else +			{ +				return NULL; +			}  		}  	} @@ -2681,14 +2718,8 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa  		((LLFloater*)getParent())->setFocus(TRUE);  	} -	item_list_t::reverse_iterator cur_item_iter; -	for (cur_item_iter = mItems.rbegin(); cur_item_iter != mItems.rend(); ++cur_item_iter) -	{ -		if( (*cur_item_iter) == cur_item) -		{ -			break; -		} -	} +	// Current item reverse position from the end of the list +	item_list_t::reverse_iterator cur_item_iter = std::find(mItems.rbegin(), mItems.rend(), cur_item);  	item_list_t::reverse_iterator prev_item_iter;  	if (cur_item_iter == mItems.rend()) @@ -2699,9 +2730,37 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa  	{  		prev_item_iter = cur_item_iter;  		prev_item_iter++; + +		// First visible item reverse position in the items list +		item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem); +  		if (prev_item_iter == mItems.rend())  		{  			prev_item_iter = mItems.rbegin(); + +			// If current item is the first in the list, the menu is scrolled to the end +			// and the last item is highlighted. +			if (mScrollable && !scrollItems(SD_END)) +			{ +				return NULL; +			} +		} +		// If current item is the first visible, the menu is scrolled one item up +		// and the previous item is highlighted. +		else if (mScrollable && +				 std::distance(first_visible_item_iter, cur_item_iter) <= 0) +		{ +			// Call highlightNextItem() only if the menu was successfully scrolled up. +			// If scroll timer hasn't expired yet the menu won't be scrolled and calling +			// highlightNextItem() will result in an endless recursion. +			if (scrollItems(SD_UP)) +			{ +				return highlightPrevItem(cur_item, skip_disabled); +			} +			else +			{ +				return NULL; +			}  		}  	} @@ -2872,12 +2931,12 @@ BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks )  	if( clicks > 0 )  	{  		while( clicks-- ) -			scrollItemsDown(); +			scrollItems(SD_DOWN);  	}  	else  	{  		while( clicks++ ) -			scrollItemsUp(); +			scrollItems(SD_UP);  	}  	return TRUE; diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 19b738312e..35544402f4 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -397,6 +397,15 @@ public:  	static const std::string ARROW_UP;  	static const std::string ARROW_DOWN; +	// for scrollable menus +	typedef enum e_scrolling_direction +	{ +		SD_UP = 0, +		SD_DOWN = 1, +		SD_BEGIN = 2, +		SD_END = 3 +	} EScrollingDirection; +  protected:  	LLMenuGL(const LLMenuGL::Params& p);  	friend class LLUICtrlFactory; @@ -503,8 +512,7 @@ public:  	S32 getShortcutPad() { return mShortcutPad; } -	void scrollItemsUp(); -	void scrollItemsDown(); +	bool scrollItems(EScrollingDirection direction);  	BOOL isScrollable() const { return mScrollable; }  	static class LLMenuHolderGL* sMenuContainer; diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index c8e56630f1..900e2c789e 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -904,7 +904,7 @@ LLPanel *LLPanel::childGetVisiblePanelWithHelp()  		child = *it;  		// do we have a panel with a help topic?  		LLPanel *panel = dynamic_cast<LLPanel *>(child); -		if (panel && panel->getVisible() && !panel->getHelpTopic().empty()) +		if (panel && panel->isInVisibleChain() && !panel->getHelpTopic().empty())  		{  			return panel;  		} diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 9adeddca99..5721df6b36 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1622,7 +1622,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  	style_params.fillFrom(getDefaultStyleParams());  	S32 part = (S32)LLTextParser::WHOLE; -	if(mParseHTML) +	if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).  	{  		S32 start=0,end=0;  		LLUrlMatch match; @@ -2214,19 +2214,39 @@ bool LLTextBase::scrolledToEnd()  	return mScroller->isAtBottom();  } -  bool LLTextBase::setCursor(S32 row, S32 column)  { -	if (0 <= row && row < (S32)mLineInfoList.size()) +	if (row < 0 || column < 0) return false; + +	S32 n_lines = mLineInfoList.size(); +	for (S32 line = row; line < n_lines; ++line)  	{ -		S32 doc_pos = mLineInfoList[row].mDocIndexStart; -		column = llclamp(column, 0, mLineInfoList[row].mDocIndexEnd - mLineInfoList[row].mDocIndexStart - 1); -		doc_pos += column; -		updateCursorXPos(); +		const line_info& li = mLineInfoList[line]; + +		if (li.mLineNum < row) +		{ +			continue; +		} +		else if (li.mLineNum > row) +		{ +			break; // invalid column specified +		} + +		// Found the given row. +		S32 line_length = li.mDocIndexEnd - li.mDocIndexStart;; +		if (column >= line_length) +		{ +			column -= line_length; +			continue; +		} +		// Found the given column. +		updateCursorXPos(); +		S32 doc_pos = li.mDocIndexStart + column;  		return setCursorPos(doc_pos);  	} -	return false; + +	return false; // invalid row or column specified  } diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp index 0eb2dc1387..d29260750f 100644 --- a/indra/llui/lltoggleablemenu.cpp +++ b/indra/llui/lltoggleablemenu.cpp @@ -35,10 +35,22 @@ static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu");  LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p)  :	LLMenuGL(p),  	mButtonRect(), +	mVisibilityChangeSignal(NULL),  	mClosedByButtonClick(false)  {  } +LLToggleableMenu::~LLToggleableMenu() +{ +	delete mVisibilityChangeSignal; +} + +boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const commit_signal_t::slot_type& cb) +{ +	if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t(); +	return mVisibilityChangeSignal->connect(cb); +} +  // virtual  void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)  { @@ -49,6 +61,12 @@ void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)  	{  		mClosedByButtonClick = true;  	} + +	if (mVisibilityChangeSignal) +	{ +		(*mVisibilityChangeSignal)(this, +				LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick)); +	}  }  void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view) diff --git a/indra/llui/lltoggleablemenu.h b/indra/llui/lltoggleablemenu.h index f036cdfffb..2094bd776f 100644 --- a/indra/llui/lltoggleablemenu.h +++ b/indra/llui/lltoggleablemenu.h @@ -41,6 +41,10 @@ protected:  	LLToggleableMenu(const Params&);  	friend class LLUICtrlFactory;  public: +	~LLToggleableMenu(); + +	boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb ); +  	virtual void handleVisibilityChange (BOOL curVisibilityIn);  	const LLRect& getButtonRect() const { return mButtonRect; } @@ -57,6 +61,7 @@ public:  protected:  	bool mClosedByButtonClick;  	LLRect mButtonRect; +	commit_signal_t*	mVisibilityChangeSignal;  };  #endif // LL_LLTOGGLEABLEMENU_H diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index eff2467bf0..4faa0e070e 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -58,10 +58,12 @@ class LLUIString  public:  	// These methods all perform appropriate argument substitution  	// and modify mOrig where appropriate -        LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {} +	LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}  	LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args);  	LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); } +	~LLUIString() { delete mArgs; } +  	void assign(const std::string& instring);  	LLUIString& operator=(const std::string& s) { assign(s); return *this; } @@ -81,14 +83,14 @@ public:  	void clear();  	void clearArgs() { if (mArgs) mArgs->clear(); } -	 +  	// These utility functions are included for text editing.  	// They do not affect mOrig and do not perform argument substitution  	void truncate(S32 maxchars);  	void erase(S32 charidx, S32 len);  	void insert(S32 charidx, const LLWString& wchars);  	void replace(S32 charidx, llwchar wc); -	 +  private:  	// something changed, requiring reformatting of strings  	void dirty(); @@ -100,7 +102,7 @@ private:  	void updateResult() const;  	void updateWResult() const;  	LLStringUtil::format_map_t& getArgs(); -	 +  	std::string mOrig;  	mutable std::string mResult;  	mutable LLWString mWResult; // for displaying diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index efb3f1a8be..6cc72bad82 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -978,7 +978,7 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const  //  LLUrlEntryNoLink::LLUrlEntryNoLink()  { -	mPattern = boost::regex("<nolink>[^<]*</nolink>", +	mPattern = boost::regex("<nolink>.*</nolink>",  							boost::regex::perl|boost::regex::icase);  } @@ -995,7 +995,8 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC  LLStyle::Params LLUrlEntryNoLink::getStyle() const   {  -	return LLStyle::Params();  +	// Don't render as URL (i.e. no context menu or hand cursor). +	return LLStyle::Params().is_link(false);  } | 
