Skip to content
Snippets Groups Projects
lltabcontainer.cpp 48.9 KiB
Newer Older
}

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()) return FALSE;
James Cook's avatar
James Cook committed
	if (which < 0) return FALSE;

	//if( gFocusMgr.childHasKeyboardFocus( this ) )
	//{
Jon Wolk's avatar
Jon Wolk committed
	//	gFocusMgr.setKeyboardFocus( NULL );
	LLTabTuple* selected_tuple = getTab(which);
James Cook's avatar
James Cook committed
	if (!selected_tuple)
	{
		return FALSE;
	}
	
	BOOL is_visible = FALSE;
	if (getTab(which)->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
			
			if( is_selected && (mIsVertical || (getMaxScrollPos() > 0)))
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
					{
						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
				}
			}
			i++;
		}
		if( selected_tuple->mOnChangeCallback )
		{
			selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false );
		}
	}
	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)
{
	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
		{
			const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
			// 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->setRightHPad(6);
			tuple->mButton->reshape(llclamp(fontp->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::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::setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*, bool))
{
	LLTabTuple* tuplep = getTabByPanel(tab);
	if (tuplep)
	{
		tuplep->mOnChangeCallback = on_tab_clicked;
void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata)
{
	LLTabTuple* tuplep = getTabByPanel(tab);
	if (tuplep)
	{
		tuplep->mUserData = userdata;
	}
}
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
{
	if (index >= 0 && index < getTabCount())
	{
		LLTabTuple* tuple = getTab(index);
		LLButton* tab_button = tuple->mButton;
		const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
		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


// static 
void LLTabContainer::onTabBtn( void* userdata )
{
	LLTabTuple* tuple = (LLTabTuple*) userdata;
	LLTabContainer* self = tuple->mTabContainer;
	self->selectTabPanel( tuple->mTabPanel );
	
	if( tuple->mOnChangeCallback )
	{
		tuple->mOnChangeCallback( tuple->mUserData, true );
James Cook's avatar
James Cook committed
	}

	tuple->mTabPanel->setFocus(TRUE);
}

// static 
void LLTabContainer::onCloseBtn( void* userdata )
{
	LLTabContainer* self = (LLTabContainer*) userdata;
	if( self->mCloseCallback )
James Cook's avatar
James Cook committed
	{
		self->mCloseCallback( self->mCallbackUserdata );
James Cook's avatar
James Cook committed
	}
James Cook's avatar
James Cook committed

// static 
void LLTabContainer::onNextBtn( void* userdata )
{
	// Scroll tabs to the left
	LLTabContainer* self = (LLTabContainer*) userdata;
	if (!self->mScrolled)
James Cook's avatar
James Cook committed
	{
James Cook's avatar
James Cook committed
	}
// static 
void LLTabContainer::onNextBtnHeld( void* userdata )
James Cook's avatar
James Cook committed
{
	LLTabContainer* self = (LLTabContainer*) userdata;
	if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
	{
		self->mScrollTimer.reset();
		self->scrollNext();
		self->mScrolled = TRUE;
	}
}
James Cook's avatar
James Cook committed

// static 
void LLTabContainer::onPrevBtn( void* userdata )
{
	LLTabContainer* self = (LLTabContainer*) userdata;
	if (!self->mScrolled)
	{
		self->scrollPrev();
James Cook's avatar
James Cook committed
	}
	self->mScrolled = FALSE;
}

// static 
void LLTabContainer::onJumpFirstBtn( void* userdata )
{
	LLTabContainer* self = (LLTabContainer*) userdata;
	self->mScrollPos = 0;
}

// static 
void LLTabContainer::onJumpLastBtn( void* userdata )
{
	LLTabContainer* self = (LLTabContainer*) userdata;
	self->mScrollPos = self->mMaxScrollPos;
}

// static 
void LLTabContainer::onPrevBtnHeld( void* userdata )
{
	LLTabContainer* self = (LLTabContainer*) userdata;
	if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
James Cook's avatar
James Cook committed
	{
		self->mScrollTimer.reset();
		self->scrollPrev();
		self->mScrolled = TRUE;
// static
LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
James Cook's avatar
James Cook committed
{
	std::string name("tab_container");
James Cook's avatar
James Cook committed

	// Figure out if we are creating a vertical or horizontal tab container.
	bool is_vertical = false;
	LLTabContainer::TabPosition tab_position = LLTabContainer::TOP;
	if (node->hasAttribute("tab_position"))
James Cook's avatar
James Cook committed
	{
		std::string tab_position_string;
		node->getAttributeString("tab_position", tab_position_string);
		LLStringUtil::toLower(tab_position_string);
			tab_position = LLTabContainer::TOP;
			is_vertical = false;
		else if ("bottom" == tab_position_string)
James Cook's avatar
James Cook committed
		{
			tab_position = LLTabContainer::BOTTOM;
			is_vertical = false;
James Cook's avatar
James Cook committed
		}
James Cook's avatar
James Cook committed
		{
	BOOL border = FALSE;
	node->getAttributeBOOL("border", border);

	LLTabContainer*	tab_container = new LLTabContainer(name, LLRect::null, tab_position, border, is_vertical);
	
	S32 tab_min_width = tab_container->mMinTabWidth;
	if (node->hasAttribute("tab_width"))
James Cook's avatar
James Cook committed
	{
		node->getAttributeS32("tab_width", tab_min_width);
	}
	else if( node->hasAttribute("tab_min_width"))
	{
		node->getAttributeS32("tab_min_width", tab_min_width);
	S32	tab_max_width = tab_container->mMaxTabWidth;
	if (node->hasAttribute("tab_max_width"))
James Cook's avatar
James Cook committed
	{
		node->getAttributeS32("tab_max_width", tab_max_width);
	}

	tab_container->setMinTabWidth(tab_min_width); 
	tab_container->setMaxTabWidth(tab_max_width); 
	
	BOOL hidden(tab_container->getTabsHidden());
	node->getAttributeBOOL("hide_tabs", hidden);
	tab_container->setTabsHidden(hidden);

	tab_container->setPanelParameters(node, parent);

	if (LLFloater::getFloaterHost())
	{
		LLFloater::getFloaterHost()->setTabContainer(tab_container);
	}

	//parent->addChild(tab_container);

	// Add all tab panels.
	LLXMLNodePtr child;
	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
	{
		LLView *control = factory->createCtrlWidget(tab_container, child);
		if (control && control->isPanel())
James Cook's avatar
James Cook committed
		{
			child->getAttributeString("label", label);
			if (label.empty())
James Cook's avatar
James Cook committed
			{
James Cook's avatar
James Cook committed
			}
			BOOL placeholder = FALSE;
			child->getAttributeBOOL("placeholder", placeholder);
			tab_container->addTabPanel(panelp, label, false,

	tab_container->selectFirstTab();

	tab_container->postBuild();

	tab_container->initButtons(); // now that we have the correct rect
	
	return tab_container;
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
	}
	
	std::string out_id;
	std::string in_id;
James Cook's avatar
James Cook committed

	if (mIsVertical)
	{
		// 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;

		LLRect up_arrow_btn_rect;
		up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );

		LLRect down_arrow_btn_rect;
		down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );

		out_id = "UIImgBtnScrollUpOutUUID";
		in_id = "UIImgBtnScrollUpInUUID";
		mPrevArrowBtn = new LLButton(std::string("Up Arrow"), up_arrow_btn_rect,
									 out_id, in_id, LLStringUtil::null,
									 &onPrevBtn, this, NULL );
		mPrevArrowBtn->setFollowsTop();
		mPrevArrowBtn->setFollowsLeft();

		out_id = "UIImgBtnScrollDownOutUUID";
		in_id = "UIImgBtnScrollDownInUUID";
		mNextArrowBtn = new LLButton(std::string("Down Arrow"), down_arrow_btn_rect,
									 out_id, in_id, LLStringUtil::null,
									 &onNextBtn, this, NULL );
		mNextArrowBtn->setFollowsBottom();
		mNextArrowBtn->setFollowsLeft();
	}
	else // Horizontal
	{
		S32 arrow_fudge = 1;		//  match new art better 

		// tabs on bottom reserve room for resize handle (just in case)
		if (getTabPosition() == BOTTOM)
James Cook's avatar
James Cook committed
		{
			mRightTabBtnOffset = RESIZE_HANDLE_WIDTH;
		// 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;

		LLRect left_arrow_btn_rect;
		left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+TABCNTR_ARROW_BTN_SIZE, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );

		LLRect jump_left_arrow_btn_rect;
		jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );

		S32 right_pad = TABCNTR_ARROW_BTN_SIZE + LLPANEL_BORDER_WIDTH + 1;

		LLRect right_arrow_btn_rect;
		right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - TABCNTR_ARROW_BTN_SIZE,
												btn_top + arrow_fudge,
												TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );


		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, TABCNTR_ARROW_BTN_SIZE );

		out_id = "UIImgBtnJumpLeftOutUUID";
		in_id = "UIImgBtnJumpLeftInUUID";
		mJumpPrevArrowBtn = new LLButton(std::string("Jump Left Arrow"), jump_left_arrow_btn_rect,
										 out_id, in_id, LLStringUtil::null,
										 &LLTabContainer::onJumpFirstBtn, this, LLFontGL::sSansSerif );
		mJumpPrevArrowBtn->setFollowsLeft();

		out_id = "UIImgBtnScrollLeftOutUUID";
		in_id = "UIImgBtnScrollLeftInUUID";
		mPrevArrowBtn = new LLButton(std::string("Left Arrow"), left_arrow_btn_rect,
									 out_id, in_id, LLStringUtil::null,
									 &LLTabContainer::onPrevBtn, this, LLFontGL::sSansSerif );
		mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld);
		mPrevArrowBtn->setFollowsLeft();
	
		out_id = "UIImgBtnJumpRightOutUUID";
		in_id = "UIImgBtnJumpRightInUUID";
		mJumpNextArrowBtn = new LLButton(std::string("Jump Right Arrow"), jump_right_arrow_btn_rect,
										 out_id, in_id, LLStringUtil::null,
										 &LLTabContainer::onJumpLastBtn, this,
										 LLFontGL::sSansSerif);
		mJumpNextArrowBtn->setFollowsRight();

		out_id = "UIImgBtnScrollRightOutUUID";
		in_id = "UIImgBtnScrollRightInUUID";
		mNextArrowBtn = new LLButton(std::string("Right Arrow"), right_arrow_btn_rect,
									 out_id, in_id, LLStringUtil::null,
									 &LLTabContainer::onNextBtn, this,
									 LLFontGL::sSansSerif);
		mNextArrowBtn->setFollowsRight();

		if( getTabPosition() == TOP )
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->setHeldDownCallback(onPrevBtnHeld);
	mPrevArrowBtn->setSaveToXML(false);
	mPrevArrowBtn->setTabStop(FALSE);
	addChild(mPrevArrowBtn);
James Cook's avatar
James Cook committed

	mNextArrowBtn->setHeldDownCallback(onNextBtnHeld);
	mNextArrowBtn->setSaveToXML(false);
	mNextArrowBtn->setTabStop(FALSE);
	addChild(mNextArrowBtn);
James Cook's avatar
James Cook committed

James Cook's avatar
James Cook committed
	{
		mJumpPrevArrowBtn->setSaveToXML(false);
		mJumpPrevArrowBtn->setTabStop(FALSE);
		addChild(mJumpPrevArrowBtn);
James Cook's avatar
James Cook committed
	}
James Cook's avatar
James Cook committed
	{
		mJumpNextArrowBtn->setSaveToXML(false);
		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

LLTabContainer::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
{
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
		{
			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
		}
	}
	else
	{
		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);
			// subtract off reserved portion on left
			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)
		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
		{
			LLTabTuple* tuple = *iter;
			tuple->mButton->setVisible( TRUE );
			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();
			}
		}