Newer
Older
Steven Bennetts
committed
* @brief LLTabContainer class
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "lltabcontainer.h"
#include "llfocusmgr.h"
#include "llbutton.h"
#include "llrect.h"
#include "llresmgr.h"
#include "llresizehandle.h"
#include "lltextbox.h"
#include "llcriticaldamp.h"
#include "lluictrlfactory.h"
#include "lltabcontainervertical.h"
#include "llrender.h"
const F32 SCROLL_DELAY_TIME = 0.5f;
const S32 TAB_PADDING = 15;
const S32 TABCNTR_TAB_MIN_WIDTH = 60;
Steven Bennetts
committed
const S32 TABCNTR_VERT_TAB_MIN_WIDTH = 100;
const S32 TABCNTR_TAB_MAX_WIDTH = 150;
const S32 TABCNTR_TAB_PARTIAL_WIDTH = 12; // When tabs are parially obscured, how much can you still see.
const S32 TABCNTR_TAB_HEIGHT = 16;
const S32 TABCNTR_ARROW_BTN_SIZE = 16;
const S32 TABCNTR_BUTTON_PANEL_OVERLAP = 1; // how many pixels the tab buttons and tab panels overlap.
const S32 TABCNTR_TAB_H_PAD = 4;
Steven Bennetts
committed
const S32 TABCNTR_CLOSE_BTN_SIZE = 16;
const S32 TABCNTR_HEADER_HEIGHT = LLPANEL_BORDER_WIDTH + TABCNTR_CLOSE_BTN_SIZE;
Steven Bennetts
committed
const S32 TABCNTRV_CLOSE_BTN_SIZE = 16;
const S32 TABCNTRV_HEADER_HEIGHT = LLPANEL_BORDER_WIDTH + TABCNTRV_CLOSE_BTN_SIZE;
//const S32 TABCNTRV_TAB_WIDTH = 100;
const S32 TABCNTRV_ARROW_BTN_SIZE = 16;
const S32 TABCNTRV_PAD = 0;
static LLRegisterWidget<LLTabContainer> r("tab_container");
Steven Bennetts
committed
LLTabContainer::LLTabContainer(const std::string& name, const LLRect& rect, TabPosition pos,
Steven Bennetts
committed
BOOL bordered, BOOL is_vertical )
:
LLPanel(name, rect, bordered),
mCurrentTabIdx(-1),
mNextTabIdx(-1),
mScrolled(FALSE),
mScrollPos(0),
mScrollPosPixels(0),
mMaxScrollPos(0),
Steven Bennetts
committed
mCloseCallback( NULL ),
mCallbackUserdata( NULL ),
mTitleBox(NULL),
mTopBorderHeight(LLPANEL_BORDER_WIDTH),
mTabPosition(pos),
Steven Bennetts
committed
mLockedTabCount(0),
mMinTabWidth(TABCNTR_TAB_MIN_WIDTH),
mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH),
mPrevArrowBtn(NULL),
mNextArrowBtn(NULL),
mIsVertical(is_vertical),
// Horizontal Specific
mJumpPrevArrowBtn(NULL),
mJumpNextArrowBtn(NULL),
mRightTabBtnOffset(0),
mTotalTabWidth(0)
Steven Bennetts
committed
//RN: HACK to support default min width for legacy vertical tab containers
if (mIsVertical)
{
mMinTabWidth = TABCNTR_VERT_TAB_MIN_WIDTH;
}
Steven Bennetts
committed
initButtons( );
mDragAndDropDelayTimer.stop();
Steven Bennetts
committed
LLTabContainer::~LLTabContainer()
{
std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
}
Steven Bennetts
committed
//virtual
void LLTabContainer::setValue(const LLSD& value)
Steven Bennetts
committed
selectTab((S32) value.asInteger());
}
//virtual
void LLTabContainer::reshape(S32 width, S32 height, BOOL called_from_parent)
Steven Bennetts
committed
LLPanel::reshape( width, height, called_from_parent );
updateMaxScrollPos();
Steven Bennetts
committed
//virtual
LLView* LLTabContainer::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const
{
tuple_list_t::const_iterator itor;
for (itor = mTabList.begin(); itor != mTabList.end(); ++itor)
{
LLPanel *panel = (*itor)->mTabPanel;
if (panel->getName() == name)
{
return panel;
}
}
if (recurse)
{
for (itor = mTabList.begin(); itor != mTabList.end(); ++itor)
{
LLPanel *panel = (*itor)->mTabPanel;
LLView *child = panel->getChildView(name, recurse, FALSE);
return LLView::getChildView(name, recurse, create_if_missing);
Steven Bennetts
committed
// virtual
void LLTabContainer::draw()
Steven Bennetts
committed
S32 target_pixel_scroll = 0;
S32 cur_scroll_pos = getScrollPos();
Steven Bennetts
committed
if (cur_scroll_pos > 0)
if (!mIsVertical)
S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1);
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
Steven Bennetts
committed
{
if (cur_scroll_pos == 0)
{
break;
}
target_pixel_scroll += (*iter)->mButton->getRect().getWidth();
cur_scroll_pos--;
Steven Bennetts
committed
}
// Show part of the tab to the left of what is fully visible
target_pixel_scroll -= TABCNTR_TAB_PARTIAL_WIDTH;
// clamp so that rightmost tab never leaves right side of screen
target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll);
}
else
{
S32 available_height_with_arrows = getRect().getHeight() - getTopBorderHeight() - (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1);
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
{
if (cur_scroll_pos==0)
{
break;
}
target_pixel_scroll += (*iter)->mButton->getRect().getHeight();
cur_scroll_pos--;
}
S32 total_tab_height = (BTN_HEIGHT + TABCNTRV_PAD) * getTabCount() + TABCNTRV_PAD;
// clamp so that the bottom tab never leaves bottom of panel
target_pixel_scroll = llmin(total_tab_height - available_height_with_arrows, target_pixel_scroll);
}
Steven Bennetts
committed
setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f)));
BOOL has_scroll_arrows = (mMaxScrollPos > 0) || (mScrollPosPixels > 0);
if (!mIsVertical)
mJumpPrevArrowBtn->setVisible( has_scroll_arrows );
mJumpNextArrowBtn->setVisible( has_scroll_arrows );
}
mPrevArrowBtn->setVisible( has_scroll_arrows );
mNextArrowBtn->setVisible( has_scroll_arrows );
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
S32 left = 0, top = 0;
if (mIsVertical)
{
top = getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? TABCNTRV_ARROW_BTN_SIZE : 0);
top += getScrollPosPixels();
}
else
{
// Set the leftmost position of the tab buttons.
left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (TABCNTR_ARROW_BTN_SIZE * 2) : TABCNTR_TAB_H_PAD);
left -= getScrollPosPixels();
}
// Hide all the buttons
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
{
LLTabTuple* tuple = *iter;
tuple->mButton->setVisible( FALSE );
}
LLPanel::draw();
// if tabs are hidden, don't draw them and leave them in the invisible state
if (!getTabsHidden())
{
// Show all the buttons
Steven Bennetts
committed
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
{
LLTabTuple* tuple = *iter;
tuple->mButton->setVisible( TRUE );
Steven Bennetts
committed
}
// Draw some of the buttons...
LLRect clip_rect = getLocalRect();
if (has_scroll_arrows)
Steven Bennetts
committed
{
// ...but clip them.
if (mIsVertical)
Steven Bennetts
committed
{
clip_rect.mBottom = mNextArrowBtn->getRect().mTop + 3*TABCNTRV_PAD;
clip_rect.mTop = mPrevArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD;
Steven Bennetts
committed
}
Steven Bennetts
committed
{
clip_rect.mLeft = mPrevArrowBtn->getRect().mRight;
clip_rect.mRight = mNextArrowBtn->getRect().mLeft;
Steven Bennetts
committed
}
}
LLLocalClipRect clip(clip_rect);
S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos();
S32 idx = 0;
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
{
LLTabTuple* tuple = *iter;
tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0,
top ? top - tuple->mButton->getRect().mTop : 0 );
if (top) top -= BTN_HEIGHT + TABCNTRV_PAD;
if (left) left += tuple->mButton->getRect().getWidth();
if (!mIsVertical)
{
if( idx < getScrollPos() )
Steven Bennetts
committed
{
if( tuple->mButton->getFlashing() )
Steven Bennetts
committed
{
mPrevArrowBtn->setFlashing( TRUE );
Steven Bennetts
committed
}
}
else if( max_scroll_visible < idx )
Steven Bennetts
committed
{
if( tuple->mButton->getFlashing() )
{
mNextArrowBtn->setFlashing( TRUE );
}
Steven Bennetts
committed
}
}
LLUI::pushMatrix();
Steven Bennetts
committed
{
LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f);
tuple->mButton->draw();
Steven Bennetts
committed
}
LLUI::popMatrix();
idx++;
Steven Bennetts
committed
}
if( mIsVertical && has_scroll_arrows )
{
// Redraw the arrows so that they appears on top.
gGL.pushMatrix();
gGL.translatef((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f);
mPrevArrowBtn->draw();
gGL.popMatrix();
gGL.pushMatrix();
gGL.translatef((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f);
mNextArrowBtn->draw();
gGL.popMatrix();
}
Steven Bennetts
committed
}
mPrevArrowBtn->setFlashing(FALSE);
mNextArrowBtn->setFlashing(FALSE);
Steven Bennetts
committed
// virtual
BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
Steven Bennetts
committed
BOOL handled = FALSE;
BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
Steven Bennetts
committed
if (has_scroll_arrows)
Steven Bennetts
committed
if (mJumpPrevArrowBtn&& mJumpPrevArrowBtn->getRect().pointInRect(x, y))
Steven Bennetts
committed
S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
handled = mJumpPrevArrowBtn->handleMouseDown(local_x, local_y, mask);
}
else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
handled = mJumpNextArrowBtn->handleMouseDown(local_x, local_y, mask);
}
else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
handled = mPrevArrowBtn->handleMouseDown(local_x, local_y, mask);
}
else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mNextArrowBtn->getRect().mLeft;
S32 local_y = y - mNextArrowBtn->getRect().mBottom;
handled = mNextArrowBtn->handleMouseDown(local_x, local_y, mask);
Steven Bennetts
committed
if (!handled)
{
handled = LLPanel::handleMouseDown( x, y, mask );
}
S32 tab_count = getTabCount();
if (tab_count > 0)
Steven Bennetts
committed
LLTabTuple* firsttuple = getTab(0);
LLRect tab_rect;
if (mIsVertical)
Steven Bennetts
committed
tab_rect = LLRect(firsttuple->mButton->getRect().mLeft,
has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD : mPrevArrowBtn->getRect().mTop,
firsttuple->mButton->getRect().mRight,
has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD : mNextArrowBtn->getRect().mBottom );
}
else
{
tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft,
firsttuple->mButton->getRect().mTop,
has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight,
firsttuple->mButton->getRect().mBottom );
}
if( tab_rect.pointInRect( x, y ) )
{
S32 index = getCurrentPanelIndex();
index = llclamp(index, 0, tab_count-1);
LLButton* tab_button = getTab(index)->mButton;
Steven Bennetts
committed
gFocusMgr.setMouseCapture(this);
gFocusMgr.setKeyboardFocus(tab_button);
Steven Bennetts
committed
return handled;
Steven Bennetts
committed
// virtual
BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask )
Steven Bennetts
committed
BOOL handled = FALSE;
BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
if (has_scroll_arrows)
Steven Bennetts
committed
if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
Steven Bennetts
committed
S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
handled = mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
Steven Bennetts
committed
else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
Steven Bennetts
committed
S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
handled = mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
}
else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
handled = mPrevArrowBtn->handleHover(local_x, local_y, mask);
}
else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mNextArrowBtn->getRect().mLeft;
S32 local_y = y - mNextArrowBtn->getRect().mBottom;
handled = mNextArrowBtn->handleHover(local_x, local_y, mask);
Steven Bennetts
committed
if (!handled)
Steven Bennetts
committed
handled = LLPanel::handleHover(x, y, mask);
Steven Bennetts
committed
commitHoveredButton(x, y);
return handled;
Steven Bennetts
committed
// virtual
BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
Steven Bennetts
committed
BOOL handled = FALSE;
BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
Steven Bennetts
committed
if (has_scroll_arrows)
{
Steven Bennetts
committed
if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
}
else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask);
}
else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
}
else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mNextArrowBtn->getRect().mLeft;
S32 local_y = y - mNextArrowBtn->getRect().mBottom;
handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask);
}
}
Steven Bennetts
committed
if (!handled)
Steven Bennetts
committed
handled = LLPanel::handleMouseUp( x, y, mask );
Steven Bennetts
committed
commitHoveredButton(x, y);
LLPanel* cur_panel = getCurrentPanel();
if (hasMouseCapture())
Steven Bennetts
committed
if (cur_panel)
{
if (!cur_panel->focusFirstItem(FALSE))
{
// if nothing in the panel gets focus, make sure the new tab does
// otherwise the last tab might keep focus
getTab(getCurrentPanelIndex())->mButton->setFocus(TRUE);
}
}
gFocusMgr.setMouseCapture(NULL);
Steven Bennetts
committed
return handled;
Steven Bennetts
committed
// virtual
BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect )
Steven Bennetts
committed
BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect );
if (!handled && getTabCount() > 0)
Steven Bennetts
committed
LLTabTuple* firsttuple = getTab(0);
Steven Bennetts
committed
BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
LLRect clip;
if (mIsVertical)
Steven Bennetts
committed
clip = LLRect(firsttuple->mButton->getRect().mLeft,
has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD : mPrevArrowBtn->getRect().mTop,
firsttuple->mButton->getRect().mRight,
has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD : mNextArrowBtn->getRect().mBottom );
Steven Bennetts
committed
else
Steven Bennetts
committed
clip = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft,
firsttuple->mButton->getRect().mTop,
has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight,
firsttuple->mButton->getRect().mBottom );
Steven Bennetts
committed
if( clip.pointInRect( x, y ) )
Steven Bennetts
committed
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;
handled = tuple->mButton->handleToolTip( local_x, local_y, msg, sticky_rect );
if( handled )
{
break;
}
}
Steven Bennetts
committed
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
Steven Bennetts
committed
LLTabTuple* tuple = *iter;
tuple->mButton->setVisible( FALSE );
Steven Bennetts
committed
return handled;
}
Steven Bennetts
committed
// virtual
BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask)
Steven Bennetts
committed
{
BOOL handled = FALSE;
if (key == KEY_LEFT && mask == MASK_ALT)
Steven Bennetts
committed
selectPrevTab();
handled = TRUE;
}
else if (key == KEY_RIGHT && mask == MASK_ALT)
{
selectNextTab();
handled = TRUE;
Steven Bennetts
committed
if (handled)
Steven Bennetts
committed
if (getCurrentPanel())
Steven Bennetts
committed
getCurrentPanel()->setFocus(TRUE);
Steven Bennetts
committed
if (!gFocusMgr.childHasKeyboardFocus(getCurrentPanel()))
Steven Bennetts
committed
// if child has focus, but not the current panel, focus is on a button
if (mIsVertical)
Steven Bennetts
committed
switch(key)
{
case KEY_UP:
selectPrevTab();
handled = TRUE;
break;
case KEY_DOWN:
selectNextTab();
handled = TRUE;
break;
case KEY_LEFT:
handled = TRUE;
break;
case KEY_RIGHT:
if (getTabPosition() == LEFT && getCurrentPanel())
{
getCurrentPanel()->setFocus(TRUE);
}
handled = TRUE;
break;
default:
break;
}
Steven Bennetts
committed
else
Steven Bennetts
committed
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
switch(key)
{
case KEY_UP:
if (getTabPosition() == BOTTOM && getCurrentPanel())
{
getCurrentPanel()->setFocus(TRUE);
}
handled = TRUE;
break;
case KEY_DOWN:
if (getTabPosition() == TOP && getCurrentPanel())
{
getCurrentPanel()->setFocus(TRUE);
}
handled = TRUE;
break;
case KEY_LEFT:
selectPrevTab();
handled = TRUE;
break;
case KEY_RIGHT:
selectNextTab();
handled = TRUE;
break;
default:
break;
}
Steven Bennetts
committed
return handled;
Steven Bennetts
committed
// virtual
LLXMLNodePtr LLTabContainer::getXML(bool save_children) const
Steven Bennetts
committed
LLXMLNodePtr node = LLPanel::getXML();
node->createChild("tab_position", TRUE)->setStringValue((getTabPosition() == TOP ? "top" : "bottom"));
return node;
Steven Bennetts
committed
// virtual
BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType type, void* cargo_data, EAcceptance *accept, std::string &tooltip)
Steven Bennetts
committed
BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
Steven Bennetts
committed
if( mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME )
Steven Bennetts
committed
if (has_scroll_arrows)
{
if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
Steven Bennetts
committed
{
S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
}
if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
Steven Bennetts
committed
{
S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
}
if (mPrevArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
mPrevArrowBtn->handleHover(local_x, local_y, mask);
}
else if (mNextArrowBtn->getRect().pointInRect(x, y))
{
S32 local_x = x - mNextArrowBtn->getRect().mLeft;
S32 local_y = y - mNextArrowBtn->getRect().mBottom;
mNextArrowBtn->handleHover(local_x, local_y, mask);
}
}
Josh Bell
committed
Steven Bennetts
committed
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();
mDragAndDropDelayTimer.stop();
}
}
Steven Bennetts
committed
return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip);
}
void LLTabContainer::addTabPanel(LLPanel* child,
const std::string& label,
BOOL select,
void (*on_tab_clicked)(void*, bool),
void* userdata,
S32 indent,
BOOL placeholder,
eInsertionPoint insertion_point)
{
if (child->getParent() == this)
{
// already a child of mine
return;
}
const LLFontGL* font = LLResMgr::getInstance()->getRes( mIsVertical ? LLFONT_SANSSERIF : LLFONT_SANSSERIF_SMALL );
// Store the original label for possible xml export.
child->setLabel(label);
std::string trimmed_label = label;
LLStringUtil::trim(trimmed_label);
Steven Bennetts
committed
S32 button_width = mMinTabWidth;
if (!mIsVertical)
{
button_width = llclamp(font->getWidth(trimmed_label) + TAB_PADDING, mMinTabWidth, mMaxTabWidth);
}
// Tab panel
S32 tab_panel_top;
S32 tab_panel_bottom;
Steven Bennetts
committed
if( getTabPosition() == LLTabContainer::TOP )
Steven Bennetts
committed
S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT;
tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP);
tab_panel_bottom = LLPANEL_BORDER_WIDTH;
}
else
{
Steven Bennetts
committed
tab_panel_top = getRect().getHeight() - getTopBorderHeight();
tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP); // Run to the edge, covering up the border
}
Steven Bennetts
committed
LLRect tab_panel_rect;
if (mIsVertical)
{
tab_panel_rect = LLRect(mMinTabWidth + (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 );
}
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().
std::string tab_img;
std::string tab_selected_img;
S32 tab_fudge = 1; // To make new tab art look better, nudge buttons up 1 pel
Steven Bennetts
committed
if (mIsVertical)
Steven Bennetts
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, TABCNTR_TAB_HEIGHT );
tab_img = "tab_top_blue.tga";
tab_selected_img = "tab_top_selected_blue.tga";
}
else
{
btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
tab_img = "tab_bottom_blue.tga";
tab_selected_img = "tab_bottom_selected_blue.tga";
Steven Bennetts
committed
LLTextBox* textbox = NULL;
LLButton* btn = NULL;
if (placeholder)
{
btn_rect.translate(0, -LLBUTTON_V_PAD-2);
Steven Bennetts
committed
textbox = new LLTextBox(trimmed_label, btn_rect, trimmed_label, font);
btn = new LLButton(LLStringUtil::null, LLRect(0,0,0,0));
Steven Bennetts
committed
if (mIsVertical)
btn = new LLButton(std::string("vert tab button"),
Steven Bennetts
committed
btn_rect,
LLStringUtil::null,
LLStringUtil::null,
LLStringUtil::null,
Steven Bennetts
committed
&LLTabContainer::onTabBtn, NULL,
font,
trimmed_label, trimmed_label);
btn->setImages(std::string("tab_left.tga"), std::string("tab_left_selected.tga"));
Steven Bennetts
committed
btn->setScaleImage(TRUE);
btn->setHAlign(LLFontGL::LEFT);
btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
btn->setTabStop(FALSE);
if (indent)
{
btn->setLeftHPad(indent);
}
std::string tooltip = trimmed_label;
Steven Bennetts
committed
tooltip += "\nAlt-Left arrow for previous tab";
tooltip += "\nAlt-Right arrow for next tab";
btn = new LLButton(std::string(child->getName()) + " tab",
Steven Bennetts
committed
btn_rect,
LLStringUtil::null, LLStringUtil::null, LLStringUtil::null,
Steven Bennetts
committed
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
&LLTabContainer::onTabBtn, NULL, // set userdata below
font,
trimmed_label, trimmed_label );
btn->setVisible( FALSE );
btn->setToolTip( tooltip );
btn->setScaleImage(TRUE);
btn->setImages(tab_img, tab_selected_img);
// Try to squeeze in a bit more text
btn->setLeftHPad( 4 );
btn->setRightHPad( 2 );
btn->setHAlign(LLFontGL::LEFT);
btn->setTabStop(FALSE);
if (indent)
{
btn->setLeftHPad(indent);
}
if( getTabPosition() == TOP )
{
btn->setFollowsTop();
}
else
{
btn->setFollowsBottom();
}
Steven Bennetts
committed
}
LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, textbox );
insertTuple( tuple, insertion_point );
Steven Bennetts
committed
if (textbox)
{
textbox->setSaveToXML(false);
addChild( textbox, 0 );
}
if (btn)
{
btn->setSaveToXML(false);
btn->setCallbackUserData( tuple );
addChild( btn, 0 );
}
Steven Bennetts
committed
if (child)
{
addChild(child, 1);
}
Steven Bennetts
committed
updateMaxScrollPos();
}
void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label)
Steven Bennetts
committed
{
addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE);
}
void LLTabContainer::removeTabPanel(LLPanel* child)
{
Steven Bennetts
committed
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
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)
{
LLTabTuple* tuple = *iter;
if( tuple->mTabPanel == child )
{
Steven Bennetts
committed
removeChild( tuple->mButton );
delete tuple->mButton;
removeChild( tuple->mTabPanel );
// delete tuple->mTabPanel;
mTabList.erase( iter );
delete tuple;
Steven Bennetts
committed
// 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();
Steven Bennetts
committed
void LLTabContainer::lockTabs(S32 num_tabs)
Steven Bennetts
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())
Steven Bennetts
committed
mTabList[which]->mButton->setEnabled(enable);
Steven Bennetts
committed
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;
Steven Bennetts
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;
}