diff options
| -rw-r--r-- | indra/llui/llmenugl.cpp | 205 | ||||
| -rw-r--r-- | indra/llui/llmenugl.h | 12 | 
2 files changed, 142 insertions, 75 deletions
| 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; | 
