Skip to content
Snippets Groups Projects
lltabcontainer.cpp 59.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Steven Bennetts's avatar
    Steven Bennetts committed
    		}
    		else
    		{
    			tab_panel_top = getRect().getHeight() - getTopBorderHeight();
    
    			tab_panel_bottom = (mTabHeight - tabcntr_button_panel_overlap);  // Run to the edge, covering up the border
    
    Steven Bennetts's avatar
    Steven Bennetts committed
    		}
    
    Steven Bennetts's avatar
    Steven Bennetts committed
    		//Scip tab button space if they are invisible(EXT - 576)
    		tab_panel_top = getRect().getHeight();
    		tab_panel_bottom = LLPANEL_BORDER_WIDTH;
    
    James Cook's avatar
    James Cook committed
    	}
    
    Steven Bennetts's avatar
    Steven Bennetts committed
    
    
    Steven Bennetts's avatar
    Steven Bennetts committed
    	if (!getTabsHidden() && mIsVertical)
    
    		tab_panel_rect = LLRect(mMinTabWidth + mRightTabBtnOffset + (LLPANEL_BORDER_WIDTH * 2) + tabcntrv_pad,
    
    								getRect().getHeight() - LLPANEL_BORDER_WIDTH,
    								getRect().getWidth() - LLPANEL_BORDER_WIDTH,
    								LLPANEL_BORDER_WIDTH);
    	}
    	else
    	{
    		tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH, 
    								tab_panel_top,
    								getRect().getWidth()-LLPANEL_BORDER_WIDTH,
    								tab_panel_bottom );
    	}
    
    James Cook's avatar
    James Cook committed
    	child->setFollowsAll();
    	child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
    	child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
    	// add this child later
    
    	child->setVisible( FALSE );  // Will be made visible when selected
    
    	mTotalTabWidth += button_width;
    
    	// Tab button
    	LLRect btn_rect;  // Note: btn_rect.mLeft is just a dummy.  Will be updated in draw().
    
    	LLUIImage* tab_img = NULL;
    	LLUIImage* tab_selected_img = NULL;
    
    James Cook's avatar
    James Cook committed
    	S32 tab_fudge = 1;		//  To make new tab art look better, nudge buttons up 1 pel
    
    
    James Cook's avatar
    James Cook committed
    	{
    
    		btn_rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2,	// JC - Fudge factor
    								   (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * getTabCount()),
    
    								   mMinTabWidth,
    								   BTN_HEIGHT);
    	}
    	else if( getTabPosition() == LLTabContainer::TOP )
    	{
    
    		btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, mTabHeight);
    
    		tab_img = mMiddleTabParams.tab_top_image_unselected;
    		tab_selected_img = mMiddleTabParams.tab_top_image_selected; 
    
    		btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, mTabHeight);
    
    		tab_img = mMiddleTabParams.tab_bottom_image_unselected;
    		tab_selected_img = mMiddleTabParams.tab_bottom_image_selected;
    
    	LLTextBox* textbox = NULL;
    	LLButton* btn = NULL;
    
    	LLCustomButtonIconCtrl::Params custom_btn_params;
    	{
    		custom_btn_params.icon_ctrl_pad(mTabIconCtrlPad);
    	}
    	LLButton::Params normal_btn_params;
    
    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);
    
    		LLButton::Params& p = (mCustomIconCtrlUsed ? custom_btn_params : normal_btn_params);
    		
    		p.rect(btn_rect);
    		p.font(mFont);
    		p.font_halign = mFontHalign;
    		p.label(trimmed_label);
    		p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
    		if (indent)
    		{
    			p.pad_left(indent);
    		}
    		p.pad_bottom( mLabelPadBottom );
    		p.scale_image(true);
    		p.tab_stop(false);
    		p.label_shadow(false);
    		p.follows.flags = FOLLOWS_LEFT;
    		
    
    James Cook's avatar
    James Cook committed
    		{
    
    		  p.name("vtab_"+std::string(child->getName()));
    		  p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
    		  p.image_selected(mMiddleTabParams.tab_left_image_selected);
    		  p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
    
    James Cook's avatar
    James Cook committed
    		}
    		else
    
    		  { 
    		    p.name("htab_"+std::string(child->getName()));
    		    p.visible(false);
    		    p.image_unselected(tab_img);
    		    p.image_selected(tab_selected_img);
    		    p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);
    		    // Try to squeeze in a bit more text
    		    p.pad_left( mLabelPadLeft );
    		    p.pad_right(2);
    
    
    		// inits flash timer
    		p.button_flash_enable = mEnableTabsFlashing;
    
    		p.flash_color = mTabsFlashingColor;
    
    		
    		// *TODO : It seems wrong not to use p in both cases considering the way p is initialized
    		if (mCustomIconCtrlUsed)
    		{
    			btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params);
    		}
    		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
    	}
    
    	else
    	{
    		if (textbox)
    		{
    			LLUICtrl::addChild(textbox, 0);
    		}
    		if (btn)
    		{
    			LLUICtrl::addChild(btn, 0);
    		}
    	}
    
    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();
    
    James Cook's avatar
    James Cook committed
    	}
    
    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());
    			}
    
    
    			if (!getTabsHidden())
    			{
    				// We need to remove tab buttons only if the tabs are not hidden.
    				removeChild( tuple->mButton );
    			}
    
    
     			removeChild( tuple->mTabPanel );
    // 			delete tuple->mTabPanel;
    
    	// 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);
    
    James Cook's avatar
    James Cook committed
    	}
    
    	// Stop the DaD timer as it might run forever
    	// enableTabButton() is typically called on refresh and draw when anything changed
    	// in the tab container so it's a good time to reset that.
    	mDragAndDropDelayTimer.stop();
    
    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() && selected_tuple->mVisible )
    
    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 );
    
                // Although the selected tab must be complete, we may have hollow LLTabTuple tucked in the list
    
                {
                    tuple->mButton->setUseEllipses(mUseTabEllipses);
                    tuple->mButton->setHAlign(mFontHalign);
                    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 );
                }
    
                {
                    tuple->mTabPanel->setVisible( is_selected );
                    //tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here.
                }
    
    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
    				}
    
    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 && tuple->mButton ? tuple->mButton->getRect().getWidth() : 0);
    
    						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
    							{
    
    								running_tab_width += (other_tuple && other_tuple->mButton ? other_tuple->mButton->getRect().getWidth() : 0);
    
    								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
    	{
    
    		LL_WARNS() << "LLTabContainer::selectTabByName(" << name << ") failed" << LL_ENDL;
    
    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);
    
    
    	if (!hasButton && (icon != NULL))
    	{
    		// It was assumed that the tab's button would take ownership of the icon pointer.
    		// But since the tab did not have a button, kill the icon to prevent the memory
    		// leak.
    		icon->die();
    	}
    
    void LLTabContainer::reshapeTuple(LLTabTuple* tuple)
    
    {
    	static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
    
    		if(mCustomIconCtrlUsed)
    		{
    			LLCustomButtonIconCtrl* button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton);
    
    Tofu Linden's avatar
    Tofu Linden committed
    			LLIconCtrl* icon_ctrl = button ? button->getIconCtrl() : NULL;
    
    			image_overlay_width = icon_ctrl ? icon_ctrl->getRect().getWidth() : 0;
    		}
    		else
    		{
    			image_overlay_width = tuple->mButton->getImageOverlay().notNull() ?
    					tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : 0;
    		}
    
    		// remove current width from total tab strip width
    		mTotalTabWidth -= tuple->mButton->getRect().getWidth();
    
    		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
    	}
    
    
    	if(mCurrentTabIdx < mTabList.size()-1)
    	{
    		selectNextTab();
    	}
    
    void LLTabContainer::onNextBtnHeld( const LLSD& data )
    
    James Cook's avatar
    James Cook committed
    {
    
    	if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
    
    		mScrollTimer.reset();
    		scrollNext();
    
    
    		if(mCurrentTabIdx < mTabList.size()-1)
    		{
    			selectNextTab();
    		}
    
    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();
    
    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();