Skip to content
Snippets Groups Projects
lltabcontainer.cpp 55.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • James Cook's avatar
    James Cook committed
    	if (placeholder)
    	{
    
    		btn_rect.translate(0, -6); // *TODO: make configurable
    
    		LLTextBox::Params params;
    		params.name(trimmed_label);
    		params.rect(btn_rect);
    
    		params.font(mFont);
    
    		textbox = LLUICtrlFactory::create<LLTextBox> (params);
    
    		btn = LLUICtrlFactory::create<LLButton>(p);
    
    James Cook's avatar
    James Cook committed
    		{
    
    			LLButton::Params p;
    			p.name(std::string("vert tab button"));
    			p.rect(btn_rect);
    			p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
    			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
    
    			p.font(mFont);
    
    			p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
    			p.image_selected(mMiddleTabParams.tab_left_image_selected);
    
    			p.font_halign = mFontHalign;
    
    			p.pad_bottom( mLabelPadBottom );
    
    			if(mCustomIconCtrlUsed)
    			{
    				btn = createCustomButton(p);
    			}
    			else
    			{
    				btn = LLUICtrlFactory::create<LLButton>(p);
    			}
    
    			LLButton::Params p;
    			p.name(std::string(child->getName()) + " tab");
    			p.rect(btn_rect);
    			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
    
    			p.font(mFont);
    
    			p.label(trimmed_label);
    			p.visible(false);
    			p.scale_image(true);
    			p.image_unselected(tab_img);
    			p.image_selected(tab_selected_img);
    			p.tab_stop(false);
    
    			p.pad_left( mLabelPadLeft );
    
    			p.pad_bottom( mLabelPadBottom );
    
    			p.font_halign = mFontHalign;
    
    			p.follows.flags = FOLLOWS_LEFT;
    			p.follows.flags = FOLLOWS_LEFT;
    	
    
    				p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
    
    				p.follows.flags = p.follows.flags() | FOLLOWS_BOTTOM;
    
    			if(mCustomIconCtrlUsed)
    			{
    				btn = createCustomButton(p);
    			}
    			else
    			{
    				btn = LLUICtrlFactory::create<LLButton>(p);
    			}
    
    James Cook's avatar
    James Cook committed
    		}
    
    	LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox );
    
    James Cook's avatar
    James Cook committed
    
    
    	// if new tab was added as a first or last tab, update button image 
    	// and update button image of any tab it may have affected
    	if (tuple == mTabList.front())
    	{  
    		update_images(tuple, mFirstTabParams, getTabPosition());
    
    		if (mTabList.size() == 2) 
    		{		
    			update_images(mTabList[1], mLastTabParams, getTabPosition());
    		}
    		else if (mTabList.size() > 2) 
    		{
    			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();
    	}
    
    LLButton* LLTabContainer::createCustomButton(const LLButton::Params& p)
    {
    	LLCustomButtonIconCtrl::Params custom_btn_params;
    	LLButton::Params* btn_params_p = dynamic_cast<LLButton::Params*>(&custom_btn_params);
    
    	btn_params_p->overwriteFrom(p);
    	custom_btn_params.icon_ctrl_pad(mTabIconCtrlPad);
    	custom_btn_params.icon_ctrl_width(mTabIconCtrlWidth);
    	custom_btn_params.icon_ctrl_height(mTabIconCtrlHeight);
    
    	return LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params);
    }
    
    
    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->mButton->setUseEllipses(TRUE);
    			tuple->mButton->setHAlign(LLFontGL::LEFT);
    
    James Cook's avatar
    James Cook committed
    			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)
    {
    	LLTabTuple* tuple = getTabByPanel(child);
    	if( tuple )
    	{
    
    		tuple->mButton->setImageOverlay(image_name, LLFontGL::LEFT, color);
    
    		reshapeTuple(tuple);
    
    void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const LLColor4& color)
    {
    	LLTabTuple* tuple = getTabByPanel(child);
    	if( tuple )
    	{
    
    		tuple->mButton->setImageOverlay(image_id, LLFontGL::LEFT, color);
    
    		reshapeTuple(tuple);
    	}
    }
    
    void LLTabContainer::setTabImage(LLPanel* child, LLIconCtrl* icon)
    {
    	LLTabTuple* tuple = getTabByPanel(child);
    	LLCustomButtonIconCtrl* button;
    
    	if(tuple)
    	{
    		button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton);
    		if(button)
    		{
    			button->setIcon(icon);
    		}
    
    void LLTabContainer::reshapeTuple(LLTabTuple* tuple)
    
    {
    	static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
    	static LLUICachedControl<S32> image_left_padding ("UIButtonImageLeftPadding", 4);
    	static LLUICachedControl<S32> image_right_padding ("UIButtonImageRightPadding", 4);
    	static LLUICachedControl<S32> image_top_padding ("UIButtonImageTopPadding", 2);
    	static LLUICachedControl<S32> image_bottom_padding ("UIButtonImageBottomPadding", 2);
    
    	if (!mIsVertical)
    	{
    		tuple->mButton->setImageOverlayLeftPad(image_left_padding);
    		tuple->mButton->setImageOverlayRightPad(image_right_padding);
    		tuple->mButton->setImageOverlayTopPad(image_top_padding);
    		tuple->mButton->setImageOverlayBottomPad(image_bottom_padding);
    
    		// 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->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 );
    
    Tofu Linden's avatar
    Tofu Linden committed
    	if (tuple)
    	{
    		tuple->mTabPanel->setFocus(TRUE);
    	}
    
    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
    		}