Skip to content
Snippets Groups Projects
lltabcontainer.cpp 52.6 KiB
Newer Older
		{
			update_images(mTabList[1], mMiddleTabParams, getTabPosition());
		}
	}
	else if (tuple == mTabList.back())
	{
		update_images(tuple, mLastTabParams, getTabPosition());

		if (mTabList.size() > 2)
		{
			update_images(mTabList[mTabList.size()-2], mMiddleTabParams, getTabPosition());
		}
	}

Steven Bennetts's avatar
Steven Bennetts committed
	//Don't add button and textbox if tab buttons are invisible(EXT - 576)
	if (!getTabsHidden())
Steven Bennetts's avatar
Steven Bennetts committed
		if (textbox)
		{
			addChild( textbox, 0 );
		}
		if (btn)
		{
			addChild( btn, 0 );
		}
James Cook's avatar
James Cook committed
	}
Steven Bennetts's avatar
Steven Bennetts committed

		LLUICtrl::addChild(child, 1);

	sendChildToFront(mPrevArrowBtn);
	sendChildToFront(mNextArrowBtn);
	sendChildToFront(mJumpPrevArrowBtn);
	sendChildToFront(mJumpNextArrowBtn);
James Cook's avatar
James Cook committed
	if( select )
	{
		selectLastTab();
	}
void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label)
	addTabPanel(TabPanelParams().panel(child).label(label).is_placeholder(true));
James Cook's avatar
James Cook committed
}

void LLTabContainer::removeTabPanel(LLPanel* child)
{
	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
	if (mIsVertical)
	{
		// Fix-up button sizes
		S32 tab_count = 0;
		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
		{
			LLTabTuple* tuple = *iter;
			LLRect rect;
			rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2,	// JC - Fudge factor
								   (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * (tab_count)),
								   mMinTabWidth,
								   BTN_HEIGHT);
			if (tuple->mPlaceholderText)
			{
				tuple->mPlaceholderText->setRect(rect);
			}
			else
			{
				tuple->mButton->setRect(rect);
			}
			tab_count++;
		}
	}
	else
	{
		// Adjust the total tab width.
		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
		{
			LLTabTuple* tuple = *iter;
			if( tuple->mTabPanel == child )
			{
				mTotalTabWidth -= tuple->mButton->getRect().getWidth();
				break;
			}
		}
	}
	
	BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this);

	// If the tab being deleted is the selected one, select a different tab.
	for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
James Cook's avatar
James Cook committed
	{
		LLTabTuple* tuple = *iter;
		if( tuple->mTabPanel == child )
		{
			// update tab button images if removing the first or last tab
			if ((tuple == mTabList.front()) && (mTabList.size() > 1))
			{
				update_images(mTabList[1], mFirstTabParams, getTabPosition());
			}
			else if ((tuple == mTabList.back()) && (mTabList.size() > 2))
			{
				update_images(mTabList[mTabList.size()-2], mLastTabParams, getTabPosition());
			}

			removeChild( tuple->mButton );
 			delete tuple->mButton;

 			removeChild( tuple->mTabPanel );
// 			delete tuple->mTabPanel;
			
			mTabList.erase( iter );
			delete tuple;

	// make sure we don't have more locked tabs than we have tabs
	mLockedTabCount = llmin(getTabCount(), mLockedTabCount);

	if (mCurrentTabIdx >= (S32)mTabList.size())
	{
		mCurrentTabIdx = mTabList.size()-1;
	}
	selectTab(mCurrentTabIdx);
	if (has_focus)
	{
		LLPanel* panelp = getPanelByIndex(mCurrentTabIdx);
		if (panelp)
		{
			panelp->setFocus(TRUE);
		}
	}

	updateMaxScrollPos();
void LLTabContainer::lockTabs(S32 num_tabs)
James Cook's avatar
James Cook committed
{
	// count current tabs or use supplied value and ensure no new tabs get
	// inserted between them
	mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount();
}

void LLTabContainer::unlockTabs()
{
	mLockedTabCount = 0;
}

void LLTabContainer::enableTabButton(S32 which, BOOL enable)
{
	if (which >= 0 && which < (S32)mTabList.size())
James Cook's avatar
James Cook committed
	{
		mTabList[which]->mButton->setEnabled(enable);
void LLTabContainer::deleteAllTabs()
{
	// Remove all the tab buttons and delete them.  Also, unlink all the child panels.
	for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
	{
		LLTabTuple* tuple = *iter;
James Cook's avatar
James Cook committed

		removeChild( tuple->mButton );
		delete tuple->mButton;

 		removeChild( tuple->mTabPanel );
// 		delete tuple->mTabPanel;
	}

	// Actually delete the tuples themselves
	std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
	mTabList.clear();
	
	// And there isn't a current tab any more
	mCurrentTabIdx = -1;
}

LLPanel* LLTabContainer::getCurrentPanel()
{
	if (mCurrentTabIdx >= 0 && mCurrentTabIdx < (S32) mTabList.size())
	{
		return mTabList[mCurrentTabIdx]->mTabPanel;
	}
	return NULL;
}

S32 LLTabContainer::getCurrentPanelIndex()
{
	return mCurrentTabIdx;
}

S32 LLTabContainer::getTabCount()
James Cook's avatar
James Cook committed
{
James Cook's avatar
James Cook committed

LLPanel* LLTabContainer::getPanelByIndex(S32 index)
{
	if (index >= 0 && index < (S32)mTabList.size())
James Cook's avatar
James Cook committed
	{
James Cook's avatar
James Cook committed

S32 LLTabContainer::getIndexForPanel(LLPanel* panel)
{
	for (S32 index = 0; index < (S32)mTabList.size(); index++)
	{
		if (mTabList[index]->mTabPanel == panel)
James Cook's avatar
James Cook committed
		{
S32 LLTabContainer::getPanelIndexByTitle(const std::string& title)
{
	for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
James Cook's avatar
James Cook committed
	{
		if (title == mTabList[index]->mButton->getLabelSelected())
		{
			return index;
		}
James Cook's avatar
James Cook committed
	}
LLPanel* LLTabContainer::getPanelByName(const std::string& name)
James Cook's avatar
James Cook committed
{
	for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
James Cook's avatar
James Cook committed
	{
		LLPanel *panel = mTabList[index]->mTabPanel;
		if (name == panel->getName())
James Cook's avatar
James Cook committed
		{
	return NULL;
}

// Change the name of the button for the current tab.
void LLTabContainer::setCurrentTabName(const std::string& name)
{
	// Might not have a tab selected
	if (mCurrentTabIdx < 0) return;

	mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name);
	mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name);
}

void LLTabContainer::selectFirstTab()
{
	selectTab( 0 );
}


void LLTabContainer::selectLastTab()
{
	selectTab( mTabList.size()-1 );
}

void LLTabContainer::selectNextTab()
{
	BOOL tab_has_focus = FALSE;
	if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
	{
		tab_has_focus = TRUE;
	}
	S32 idx = mCurrentTabIdx+1;
	if (idx >= (S32)mTabList.size())
		idx = 0;
	while (!selectTab(idx) && idx != mCurrentTabIdx)
	{
		idx = (idx + 1 ) % (S32)mTabList.size();
	}

	if (tab_has_focus)
	{
		mTabList[idx]->mButton->setFocus(TRUE);
	}
}

void LLTabContainer::selectPrevTab()
{
	BOOL tab_has_focus = FALSE;
	if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
	{
		tab_has_focus = TRUE;
	}
	S32 idx = mCurrentTabIdx-1;
	if (idx < 0)
		idx = mTabList.size()-1;
	while (!selectTab(idx) && idx != mCurrentTabIdx)
	{
		idx = idx - 1;
		if (idx < 0)
			idx = mTabList.size()-1;
	}
	if (tab_has_focus)
	{
		mTabList[idx]->mButton->setFocus(TRUE);
	}
}	
James Cook's avatar
James Cook committed

BOOL LLTabContainer::selectTabPanel(LLPanel* child)
James Cook's avatar
James Cook committed
{
	S32 idx = 0;
	for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
	{
		LLTabTuple* tuple = *iter;
		if( tuple->mTabPanel == child )
		{
			return selectTab( idx );
		}
		idx++;
	}
	return FALSE;
James Cook's avatar
James Cook committed
}

BOOL LLTabContainer::selectTab(S32 which)
{
	if (which >= getTabCount() || which < 0)
		return FALSE;
James Cook's avatar
James Cook committed

	LLTabTuple* selected_tuple = getTab(which);
James Cook's avatar
James Cook committed
	if (!selected_tuple)
	{
		return FALSE;
	}
	
	LLSD cbdata;
	if (selected_tuple->mTabPanel)
		cbdata = selected_tuple->mTabPanel->getName();
	if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) )
BOOL LLTabContainer::setTab(S32 which)
{
	static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
	LLTabTuple* selected_tuple = getTab(which);
	if (!selected_tuple)
	{
		return FALSE;
	}

	if (selected_tuple->mButton->getEnabled())
James Cook's avatar
James Cook committed
	{
James Cook's avatar
James Cook committed

		S32 i = 0;
		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
		{
			LLTabTuple* tuple = *iter;
			BOOL is_selected = ( tuple == selected_tuple );
			tuple->mTabPanel->setVisible( is_selected );
// 			tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here.
			tuple->mButton->setToggleState( is_selected );
			// RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs
			tuple->mButton->setTabStop( is_selected );
James Cook's avatar
James Cook committed
			
James Cook's avatar
James Cook committed
			{
				// Make sure selected tab is within scroll region
James Cook's avatar
James Cook committed
				{
					S32 num_visible = getTabCount() - getMaxScrollPos();
					if( i >= getScrollPos() && i <= getScrollPos() + num_visible)
					{
						setCurrentPanelIndex(which);
						is_visible = TRUE;
					}
					else
					{
						is_visible = FALSE;
					}
James Cook's avatar
James Cook committed
				}
				else if (getMaxScrollPos() > 0)
James Cook's avatar
James Cook committed
				{
James Cook's avatar
James Cook committed
					{
						S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
						S32 running_tab_width = tuple->mButton->getRect().getWidth();
						S32 j = i - 1;
						S32 min_scroll_pos = i;
						if (running_tab_width < available_width_with_arrows)
James Cook's avatar
James Cook committed
						{
James Cook's avatar
James Cook committed
							{
								LLTabTuple* other_tuple = getTab(j);
								running_tab_width += other_tuple->mButton->getRect().getWidth();
								if (running_tab_width > available_width_with_arrows)
								{
									break;
								}
								j--;
James Cook's avatar
James Cook committed
							}
James Cook's avatar
James Cook committed
						}
						setScrollPos(llclamp(getScrollPos(), min_scroll_pos, i));
						setScrollPos(llmin(getScrollPos(), getMaxScrollPos()));
James Cook's avatar
James Cook committed
					}
James Cook's avatar
James Cook committed
				}
	if (mIsVertical && getCurrentPanelIndex() >= 0)
James Cook's avatar
James Cook committed
	{
		LLTabTuple* tuple = getTab(getCurrentPanelIndex());
		tuple->mTabPanel->setVisible( TRUE );
		tuple->mButton->setToggleState( TRUE );
James Cook's avatar
James Cook committed
	}
BOOL LLTabContainer::selectTabByName(const std::string& name)
James Cook's avatar
James Cook committed
{
	LLPanel* panel = getPanelByName(name);
	if (!panel)
James Cook's avatar
James Cook committed
	{
		llwarns << "LLTabContainer::selectTabByName("
			<< name << ") failed" << llendl;
		return FALSE;
	}
James Cook's avatar
James Cook committed

	BOOL result = selectTabPanel(panel);
	return result;
}

BOOL LLTabContainer::getTabPanelFlashing(LLPanel *child)
{
	LLTabTuple* tuple = getTabByPanel(child);
	if( tuple )
	{
		return tuple->mButton->getFlashing();
James Cook's avatar
James Cook committed
	}
James Cook's avatar
James Cook committed

void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state )
{
	LLTabTuple* tuple = getTabByPanel(child);
	if( tuple )
James Cook's avatar
James Cook committed
	{
James Cook's avatar
James Cook committed

void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color)
{
	static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
	LLTabTuple* tuple = getTabByPanel(child);
	if( tuple )
	{
		tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT, color);
James Cook's avatar
James Cook committed

James Cook's avatar
James Cook committed
		{
			// remove current width from total tab strip width
			mTotalTabWidth -= tuple->mButton->getRect().getWidth();
James Cook's avatar
James Cook committed

			S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? 
				tuple->mButton->getImageOverlay()->getImage()->getWidth(0) :
				0;
James Cook's avatar
James Cook committed

James Cook's avatar
James Cook committed

			tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), 
									tuple->mButton->getRect().getHeight());
			// add back in button width to total tab strip width
			mTotalTabWidth += tuple->mButton->getRect().getWidth();
James Cook's avatar
James Cook committed

			// tabs have changed size, might need to scroll to see current tab
			updateMaxScrollPos();
		}
	}
}
void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const LLColor4& color)
{
	static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
	LLTabTuple* tuple = getTabByPanel(child);
	if( tuple )
	{
		tuple->mButton->setImageOverlay(image_id, LLFontGL::RIGHT, color);

		if (!mIsVertical)
		{
			// remove current width from total tab strip width
			mTotalTabWidth -= tuple->mButton->getRect().getWidth();

			S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ?
				tuple->mButton->getImageOverlay()->getImage()->getWidth(0) :
				0;

			tuple->mPadding = image_overlay_width;

			tuple->mButton->setRightHPad(6);
			tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),
									tuple->mButton->getRect().getHeight());
			// add back in button width to total tab strip width
			mTotalTabWidth += tuple->mButton->getRect().getWidth();

			// tabs have changed size, might need to scroll to see current tab
			updateMaxScrollPos();
		}
	}
}

void LLTabContainer::setTitle(const std::string& title)
James Cook's avatar
James Cook committed

const std::string LLTabContainer::getPanelTitle(S32 index)
{
	if (index >= 0 && index < (S32)mTabList.size())
	{
		LLButton* tab_button = mTabList[index]->mButton;
		return tab_button->getLabelSelected();
	}
	return LLStringUtil::null;
James Cook's avatar
James Cook committed

void LLTabContainer::setTopBorderHeight(S32 height)
{
	mTopBorderHeight = height;
}

S32 LLTabContainer::getTopBorderHeight() const
{
	return mTopBorderHeight;
}
James Cook's avatar
James Cook committed

void LLTabContainer::setRightTabBtnOffset(S32 offset)
{
	mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 );
James Cook's avatar
James Cook committed
	mRightTabBtnOffset = offset;
	updateMaxScrollPos();
}

void LLTabContainer::setPanelTitle(S32 index, const std::string& title)
James Cook's avatar
James Cook committed
{
	static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);

	if (index >= 0 && index < getTabCount())
	{
		LLTabTuple* tuple = getTab(index);
		LLButton* tab_button = tuple->mButton;
		const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
		mTotalTabWidth -= tab_button->getRect().getWidth();
		tab_button->reshape(llclamp(fontp->getWidth(title) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight());
		mTotalTabWidth += tab_button->getRect().getWidth();
		tab_button->setLabelSelected(title);
		tab_button->setLabelUnselected(title);
	}
	updateMaxScrollPos();
}
James Cook's avatar
James Cook committed

void LLTabContainer::onTabBtn( const LLSD& data, LLPanel* panel )
	LLTabTuple* tuple = getTabByPanel(panel);
	selectTabPanel( panel );
void LLTabContainer::onNextBtn( const LLSD& data )
James Cook's avatar
James Cook committed
	{
James Cook's avatar
James Cook committed
	}
void LLTabContainer::onNextBtnHeld( const LLSD& data )
James Cook's avatar
James Cook committed
{
	if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
		mScrollTimer.reset();
		scrollNext();
		mScrolled = TRUE;
James Cook's avatar
James Cook committed

void LLTabContainer::onPrevBtn( const LLSD& data )
James Cook's avatar
James Cook committed
	}
void LLTabContainer::onJumpFirstBtn( const LLSD& data )
void LLTabContainer::onJumpLastBtn( const LLSD& data )
	mScrollPos = mMaxScrollPos;
void LLTabContainer::onPrevBtnHeld( const LLSD& data )
	if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
James Cook's avatar
James Cook committed
	{
		mScrollTimer.reset();
		scrollPrev();
		mScrolled = TRUE;
James Cook's avatar
James Cook committed
{
	// Hack:
	if (getRect().getHeight() == 0 || mPrevArrowBtn)
James Cook's avatar
James Cook committed
	{
		return; // Don't have a rect yet or already got called
	}
	
	if (mIsVertical)
	{
		static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
		// Left and right scroll arrows (for when there are too many tabs to show all at once).
		S32 btn_top = getRect().getHeight();
		S32 btn_top_lower = getRect().mBottom+tabcntrv_arrow_btn_size;
		up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size );
		down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size );

		LLButton::Params prev_btn_params;
		prev_btn_params.name(std::string("Up Arrow"));
		prev_btn_params.rect(up_arrow_btn_rect);
		prev_btn_params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
		prev_btn_params.image_unselected.name("scrollbutton_up_out_blue.tga");
		prev_btn_params.image_selected.name("scrollbutton_up_in_blue.tga");
		prev_btn_params.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2));
		mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(prev_btn_params);

		LLButton::Params next_btn_params;
		next_btn_params.name(std::string("Down Arrow"));
		next_btn_params.rect(down_arrow_btn_rect);
		next_btn_params.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_LEFT);
		next_btn_params.image_unselected.name("scrollbutton_down_out_blue.tga");
		next_btn_params.image_selected.name("scrollbutton_down_in_blue.tga");
		next_btn_params.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2));
		mNextArrowBtn = LLUICtrlFactory::create<LLButton>(next_btn_params);
		static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
		S32 arrow_fudge = 1;		//  match new art better 

		// Left and right scroll arrows (for when there are too many tabs to show all at once).
		S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : tabcntr_arrow_btn_size + 1;
		left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+tabcntr_arrow_btn_size, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight );
		jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight );
		S32 right_pad = tabcntr_arrow_btn_size + LLPANEL_BORDER_WIDTH + 1;
		right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - tabcntr_arrow_btn_size,
												tabcntr_arrow_btn_size, mTabHeight );


		LLRect jump_right_arrow_btn_rect;
		jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad,
													 btn_top + arrow_fudge,
													 tabcntr_arrow_btn_size, mTabHeight );

		LLButton::Params p;
		p.name(std::string("Jump Left Arrow"));
		p.image_unselected.name("jump_left_out.tga");
		p.image_selected.name("jump_left_in.tga");
		p.click_callback.function(boost::bind(&LLTabContainer::onJumpFirstBtn, this, _2));
		p.rect(jump_left_arrow_btn_rect);
		p.follows.flags(FOLLOWS_LEFT);
		
		mJumpPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p);

		p = LLButton::Params();
		p.name(std::string("Left Arrow"));
		p.rect(left_arrow_btn_rect);
		p.follows.flags(FOLLOWS_LEFT);
		p.image_unselected.name("scrollbutton_left_out_blue.tga");
		p.image_selected.name("scrollbutton_left_in_blue.tga");
		p.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2));
		p.mouse_held_callback.function(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2));
		
		mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p);

		p = LLButton::Params();
		p.name(std::string("Jump Right Arrow"));
		p.rect(jump_right_arrow_btn_rect);
		p.follows.flags(FOLLOWS_RIGHT);
		p.image_unselected.name("jump_right_out.tga");
		p.image_selected.name("jump_right_in.tga");
		p.click_callback.function(boost::bind(&LLTabContainer::onJumpLastBtn, this, _2));

		mJumpNextArrowBtn = LLUICtrlFactory::create<LLButton>(p);

		p = LLButton::Params();
		p.name(std::string("Right Arrow"));
		p.rect(right_arrow_btn_rect);
		p.follows.flags(FOLLOWS_RIGHT);
		p.image_unselected.name("scrollbutton_right_out_blue.tga");
		p.image_selected.name("scrollbutton_right_in_blue.tga");
		p.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2));
		p.mouse_held_callback.function(boost::bind(&LLTabContainer::onNextBtnHeld, this, _2));

		mNextArrowBtn = LLUICtrlFactory::create<LLButton>(p);
James Cook's avatar
James Cook committed
		{
			mNextArrowBtn->setFollowsTop();
			mPrevArrowBtn->setFollowsTop();
			mJumpPrevArrowBtn->setFollowsTop();
			mJumpNextArrowBtn->setFollowsTop();
		}
		else
		{
			mNextArrowBtn->setFollowsBottom();
			mPrevArrowBtn->setFollowsBottom();
			mJumpPrevArrowBtn->setFollowsBottom();
			mJumpNextArrowBtn->setFollowsBottom();
	mPrevArrowBtn->setTabStop(FALSE);
	addChild(mPrevArrowBtn);
James Cook's avatar
James Cook committed

	mNextArrowBtn->setTabStop(FALSE);
	addChild(mNextArrowBtn);
James Cook's avatar
James Cook committed

James Cook's avatar
James Cook committed
	{
		mJumpPrevArrowBtn->setTabStop(FALSE);
		addChild(mJumpPrevArrowBtn);
James Cook's avatar
James Cook committed
	}
James Cook's avatar
James Cook committed
	{
		mJumpNextArrowBtn->setTabStop(FALSE);
		addChild(mJumpNextArrowBtn);
James Cook's avatar
James Cook committed
	}
	
	// set default tab group to be panel contents
	setDefaultTabGroup(1);
}
James Cook's avatar
James Cook committed

//this is a work around for the current LLPanel::initFromParams hack
//so that it doesn't overwrite the default tab group.
//will be removed when LLPanel is fixed soon.
void LLTabContainer::initFromParams(const LLPanel::Params& p)
{
	LLPanel::initFromParams(p);

	setDefaultTabGroup(1);
}

LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child)
{
	for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
James Cook's avatar
James Cook committed
	{
		LLTabTuple* tuple = *iter;
		if( tuple->mTabPanel == child )
James Cook's avatar
James Cook committed
		{
James Cook's avatar
James Cook committed

void LLTabContainer::insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point)
{
	switch(insertion_point)
James Cook's avatar
James Cook committed
	{
	case START:
		// insert the new tab in the front of the list
		mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
		break;
	case LEFT_OF_CURRENT:
		// insert the new tab before the current tab (but not before mLockedTabCount)
James Cook's avatar
James Cook committed
		{
		tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx);
		mTabList.insert(current_iter, tuple);
		}
		break;

	case RIGHT_OF_CURRENT:
		// insert the new tab after the current tab (but not before mLockedTabCount)
		{
		tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1);
		mTabList.insert(current_iter, tuple);
James Cook's avatar
James Cook committed
		}
void LLTabContainer::updateMaxScrollPos()
James Cook's avatar
James Cook committed
{
	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
James Cook's avatar
James Cook committed
	{
		S32 tab_total_height = (BTN_HEIGHT + tabcntrv_pad) * getTabCount();
		S32 available_height = getRect().getHeight() - getTopBorderHeight();
		if( tab_total_height > available_height )
James Cook's avatar
James Cook committed
		{
			static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
			S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad);
			S32 additional_needed = tab_total_height - available_height_with_arrows;
			setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) );
			no_scroll = FALSE;
James Cook's avatar
James Cook committed
		}
		static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0);
		static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
		static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0);
		S32 tab_space = 0;
		S32 available_space = 0;
		tab_space = mTotalTabWidth;
		available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_tab_h_pad);
James Cook's avatar
James Cook committed

James Cook's avatar
James Cook committed
		{
			S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
			available_width_with_arrows -= tabcntr_tab_partial_width;

			S32 running_tab_width = 0;
			setMaxScrollPos(getTabCount());
			for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it)
				running_tab_width += (*tab_it)->mButton->getRect().getWidth();
				if (running_tab_width > available_width_with_arrows)
				{
					break;
				}
				setMaxScrollPos(getMaxScrollPos()-1);
			// in case last tab doesn't actually fit on screen, make it the last scrolling position
			setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1));
			no_scroll = FALSE;
	if (no_scroll)
	{
		setMaxScrollPos(0);
		setScrollPos(0);
	}
	if (getScrollPos() > getMaxScrollPos())
	{
		setScrollPos(getMaxScrollPos()); // maybe just enforce this via limits in setScrollPos instead?
	}
James Cook's avatar
James Cook committed
}
void LLTabContainer::commitHoveredButton(S32 x, S32 y)
Steven Bennetts's avatar
Steven Bennetts committed
	if (!getTabsHidden() && hasMouseCapture())
		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
		{
			LLTabTuple* tuple = *iter;
			S32 local_x = x - tuple->mButton->getRect().mLeft;
			S32 local_y = y - tuple->mButton->getRect().mBottom;
			if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
			{
				tuple->mButton->onCommit();
			}
		}