lltabcontainer.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 #include "lltabcontainer.h"
00034 #include "llfocusmgr.h"
00035 #include "llbutton.h"
00036 #include "llrect.h"
00037 #include "llresmgr.h"
00038 #include "llresizehandle.h"
00039 #include "lltextbox.h"
00040 #include "llcriticaldamp.h"
00041 #include "lluictrlfactory.h"
00042 #include "lltabcontainervertical.h"
00043 #include "llglimmediate.h"
00044 
00045 
00046 const F32 SCROLL_STEP_TIME = 0.4f;
00047 const F32 SCROLL_DELAY_TIME = 0.5f;
00048 const S32 TAB_PADDING = 15;
00049 const S32 TABCNTR_TAB_MIN_WIDTH = 60;
00050 const S32 TABCNTR_VERT_TAB_MIN_WIDTH = 100;
00051 const S32 TABCNTR_TAB_MAX_WIDTH = 150;
00052 const S32 TABCNTR_TAB_PARTIAL_WIDTH = 12;       // When tabs are parially obscured, how much can you still see.
00053 const S32 TABCNTR_TAB_HEIGHT = 16;
00054 const S32 TABCNTR_ARROW_BTN_SIZE = 16;
00055 const S32 TABCNTR_BUTTON_PANEL_OVERLAP = 1;  // how many pixels the tab buttons and tab panels overlap.
00056 const S32 TABCNTR_TAB_H_PAD = 4;
00057 
00058 const S32 TABCNTR_CLOSE_BTN_SIZE = 16;
00059 const S32 TABCNTR_HEADER_HEIGHT = LLPANEL_BORDER_WIDTH + TABCNTR_CLOSE_BTN_SIZE;
00060 
00061 const S32 TABCNTRV_CLOSE_BTN_SIZE = 16;
00062 const S32 TABCNTRV_HEADER_HEIGHT = LLPANEL_BORDER_WIDTH + TABCNTRV_CLOSE_BTN_SIZE;
00063 //const S32 TABCNTRV_TAB_WIDTH = 100;
00064 const S32 TABCNTRV_ARROW_BTN_SIZE = 16;
00065 const S32 TABCNTRV_PAD = 0;
00066 
00067 static LLRegisterWidget<LLTabContainer> r("tab_container");
00068 
00069 LLTabContainer::LLTabContainer(const LLString& name, const LLRect& rect, TabPosition pos,
00070                                                            BOOL bordered, BOOL is_vertical )
00071         : 
00072         LLPanel(name, rect, bordered),
00073         mCurrentTabIdx(-1),
00074         mTabsHidden(FALSE),
00075         mScrolled(FALSE),
00076         mScrollPos(0),
00077         mScrollPosPixels(0),
00078         mMaxScrollPos(0),
00079         mCloseCallback( NULL ),
00080         mCallbackUserdata( NULL ),
00081         mTitleBox(NULL),
00082         mTopBorderHeight(LLPANEL_BORDER_WIDTH),
00083         mTabPosition(pos),
00084         mLockedTabCount(0),
00085         mMinTabWidth(TABCNTR_TAB_MIN_WIDTH),
00086         mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH),
00087         mPrevArrowBtn(NULL),
00088         mNextArrowBtn(NULL),
00089         mIsVertical(is_vertical),
00090         // Horizontal Specific
00091         mJumpPrevArrowBtn(NULL),
00092         mJumpNextArrowBtn(NULL),
00093         mRightTabBtnOffset(0),
00094         mTotalTabWidth(0)
00095 { 
00096         //RN: HACK to support default min width for legacy vertical tab containers
00097         if (mIsVertical)
00098         {
00099                 mMinTabWidth = TABCNTR_VERT_TAB_MIN_WIDTH;
00100         }
00101         setMouseOpaque(FALSE);
00102         initButtons( );
00103         mDragAndDropDelayTimer.stop();
00104 }
00105 
00106 LLTabContainer::~LLTabContainer()
00107 {
00108         std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
00109 }
00110 
00111 //virtual
00112 void LLTabContainer::setValue(const LLSD& value)
00113 {
00114         selectTab((S32) value.asInteger());
00115 }
00116 
00117 //virtual
00118 void LLTabContainer::reshape(S32 width, S32 height, BOOL called_from_parent)
00119 {
00120         LLPanel::reshape( width, height, called_from_parent );
00121         updateMaxScrollPos();
00122 }
00123 
00124 //virtual
00125 LLView* LLTabContainer::getChildView(const LLString& name, BOOL recurse, BOOL create_if_missing) const
00126 {
00127         tuple_list_t::const_iterator itor;
00128         for (itor = mTabList.begin(); itor != mTabList.end(); ++itor)
00129         {
00130                 LLPanel *panel = (*itor)->mTabPanel;
00131                 if (panel->getName() == name)
00132                 {
00133                         return panel;
00134                 }
00135         }
00136 
00137         if (recurse)
00138         {
00139                 for (itor = mTabList.begin(); itor != mTabList.end(); ++itor)
00140                 {
00141                         LLPanel *panel = (*itor)->mTabPanel;
00142                         LLView *child = panel->getChildView(name, recurse, FALSE);
00143                         if (child)
00144                         {
00145                                 return child;
00146                         }
00147                 }
00148         }
00149         return LLView::getChildView(name, recurse, create_if_missing);
00150 }
00151 
00152 // virtual
00153 void LLTabContainer::draw()
00154 {
00155         S32 target_pixel_scroll = 0;
00156         S32 cur_scroll_pos = mIsVertical ? 0 : getScrollPos();
00157         if (cur_scroll_pos > 0)
00158         {
00159                 S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
00160                 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00161                 {
00162                         if (cur_scroll_pos == 0)
00163                         {
00164                                 break;
00165                         }
00166                         target_pixel_scroll += (*iter)->mButton->getRect().getWidth();
00167                         cur_scroll_pos--;
00168                 }
00169 
00170                 // Show part of the tab to the left of what is fully visible
00171                 target_pixel_scroll -= TABCNTR_TAB_PARTIAL_WIDTH;
00172                 // clamp so that rightmost tab never leaves right side of screen
00173                 target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll);
00174         }
00175 
00176         setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f)));
00177 
00178         BOOL has_scroll_arrows = (mMaxScrollPos > 0) || (mScrollPosPixels > 0);
00179         if (!mIsVertical)
00180         {
00181                 mJumpPrevArrowBtn->setVisible( has_scroll_arrows );
00182                 mJumpNextArrowBtn->setVisible( has_scroll_arrows );
00183         }
00184         mPrevArrowBtn->setVisible( has_scroll_arrows );
00185         mNextArrowBtn->setVisible( has_scroll_arrows );
00186 
00187         S32 left = 0, top = 0;
00188         if (mIsVertical)
00189         {
00190                 top = getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? TABCNTRV_ARROW_BTN_SIZE : 0);
00191                 top += getScrollPosPixels();
00192         }
00193         else
00194         {
00195                 // Set the leftmost position of the tab buttons.
00196                 left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (TABCNTR_ARROW_BTN_SIZE * 2) : TABCNTR_TAB_H_PAD);
00197                 left -= getScrollPosPixels();
00198         }
00199         
00200         // Hide all the buttons
00201         for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00202         {
00203                 LLTabTuple* tuple = *iter;
00204                 tuple->mButton->setVisible( FALSE );
00205         }
00206 
00207         LLPanel::draw();
00208 
00209         // if tabs are hidden, don't draw them and leave them in the invisible state
00210         if (!getTabsHidden())
00211         {
00212                 // Show all the buttons
00213                 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00214                 {
00215                         LLTabTuple* tuple = *iter;
00216                         tuple->mButton->setVisible( TRUE );
00217                 }
00218 
00219                 // Draw some of the buttons...
00220                 LLRect clip_rect = getLocalRect();
00221                 if (has_scroll_arrows)
00222                 {
00223                         // ...but clip them.
00224                         if (mIsVertical)
00225                         {
00226                                 clip_rect.mBottom = mNextArrowBtn->getRect().mTop + 3*TABCNTRV_PAD;
00227                                 clip_rect.mTop = mPrevArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD;
00228                         }
00229                         else
00230                         {
00231                                 clip_rect.mLeft = mPrevArrowBtn->getRect().mRight;
00232                                 clip_rect.mRight = mNextArrowBtn->getRect().mLeft;
00233                         }
00234                 }
00235                 LLLocalClipRect clip(clip_rect);
00236 
00237                 S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos();
00238                 S32 idx = 0;
00239                 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00240                 {
00241                         LLTabTuple* tuple = *iter;
00242 
00243                         tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0,
00244                                                                            top ? top - tuple->mButton->getRect().mTop : 0 );
00245                         if (top) top -= BTN_HEIGHT + TABCNTRV_PAD;
00246                         if (left) left += tuple->mButton->getRect().getWidth();
00247 
00248                         if (!mIsVertical)
00249                         {
00250                                 if( idx < getScrollPos() )
00251                                 {
00252                                         if( tuple->mButton->getFlashing() )
00253                                         {
00254                                                 mPrevArrowBtn->setFlashing( TRUE );
00255                                         }
00256                                 }
00257                                 else if( max_scroll_visible < idx )
00258                                 {
00259                                         if( tuple->mButton->getFlashing() )
00260                                         {
00261                                                 mNextArrowBtn->setFlashing( TRUE );
00262                                         }
00263                                 }
00264                         }
00265                         LLUI::pushMatrix();
00266                         {
00267                                 LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f);
00268                                 tuple->mButton->draw();
00269                         }
00270                         LLUI::popMatrix();
00271 
00272                         idx++;
00273                 }
00274 
00275 
00276                 if( mIsVertical && has_scroll_arrows )
00277                 {
00278                         // Redraw the arrows so that they appears on top.
00279                         gGL.pushMatrix();
00280                         gGL.translatef((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f);
00281                         mPrevArrowBtn->draw();
00282                         gGL.popMatrix();
00283 
00284                         gGL.pushMatrix();
00285                         gGL.translatef((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f);
00286                         mNextArrowBtn->draw();
00287                         gGL.popMatrix();
00288                 }
00289         }
00290 
00291         mPrevArrowBtn->setFlashing(FALSE);
00292         mNextArrowBtn->setFlashing(FALSE);
00293 }
00294 
00295 
00296 // virtual
00297 BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
00298 {
00299         BOOL handled = FALSE;
00300         BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
00301 
00302         if (has_scroll_arrows)
00303         {
00304                 if (mJumpPrevArrowBtn&& mJumpPrevArrowBtn->getRect().pointInRect(x, y))
00305                 {
00306                         S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
00307                         S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
00308                         handled = mJumpPrevArrowBtn->handleMouseDown(local_x, local_y, mask);
00309                 }
00310                 else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
00311                 {
00312                         S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
00313                         S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
00314                         handled = mJumpNextArrowBtn->handleMouseDown(local_x, local_y, mask);
00315                 }
00316                 else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
00317                 {
00318                         S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
00319                         S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
00320                         handled = mPrevArrowBtn->handleMouseDown(local_x, local_y, mask);
00321                 }
00322                 else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
00323                 {
00324                         S32 local_x = x - mNextArrowBtn->getRect().mLeft;
00325                         S32 local_y = y - mNextArrowBtn->getRect().mBottom;
00326                         handled = mNextArrowBtn->handleMouseDown(local_x, local_y, mask);
00327                 }
00328         }
00329         if (!handled)
00330         {
00331                 handled = LLPanel::handleMouseDown( x, y, mask );
00332         }
00333 
00334         S32 tab_count = getTabCount();
00335         if (tab_count > 0)
00336         {
00337                 LLTabTuple* firsttuple = getTab(0);
00338                 LLRect tab_rect;
00339                 if (mIsVertical)
00340                 {
00341                         tab_rect = LLRect(firsttuple->mButton->getRect().mLeft,
00342                                                           has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD : mPrevArrowBtn->getRect().mTop,
00343                                                           firsttuple->mButton->getRect().mRight,
00344                                                           has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD : mNextArrowBtn->getRect().mBottom );
00345                 }
00346                 else
00347                 {
00348                         tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft,
00349                                                           firsttuple->mButton->getRect().mTop,
00350                                                           has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight,
00351                                                           firsttuple->mButton->getRect().mBottom );
00352                 }
00353                 if( tab_rect.pointInRect( x, y ) )
00354                 {
00355                         S32 index = getCurrentPanelIndex();
00356                         index = llclamp(index, 0, tab_count-1);
00357                         LLButton* tab_button = getTab(index)->mButton;
00358                         gFocusMgr.setMouseCapture(this);
00359                         gFocusMgr.setKeyboardFocus(tab_button);
00360                 }
00361         }
00362         return handled;
00363 }
00364 
00365 // virtual
00366 BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask )
00367 {
00368         BOOL handled = FALSE;
00369         BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
00370 
00371         if (has_scroll_arrows)
00372         {
00373                 if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
00374                 {
00375                         S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
00376                         S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
00377                         handled = mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
00378                 }
00379                 else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
00380                 {
00381                         S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
00382                         S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
00383                         handled = mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
00384                 }
00385                 else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
00386                 {
00387                         S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
00388                         S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
00389                         handled = mPrevArrowBtn->handleHover(local_x, local_y, mask);
00390                 }
00391                 else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
00392                 {
00393                         S32 local_x = x - mNextArrowBtn->getRect().mLeft;
00394                         S32 local_y = y - mNextArrowBtn->getRect().mBottom;
00395                         handled = mNextArrowBtn->handleHover(local_x, local_y, mask);
00396                 }
00397         }
00398         if (!handled)
00399         {
00400                 handled = LLPanel::handleHover(x, y, mask);
00401         }
00402 
00403         commitHoveredButton(x, y);
00404         return handled;
00405 }
00406 
00407 // virtual
00408 BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
00409 {
00410         BOOL handled = FALSE;
00411         BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
00412 
00413         if (has_scroll_arrows)
00414         {
00415                 if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
00416                 {
00417                         S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
00418                         S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
00419                         handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
00420                 }
00421                 else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x,       y))
00422                 {
00423                         S32     local_x = x     - mJumpNextArrowBtn->getRect().mLeft;
00424                         S32     local_y = y     - mJumpNextArrowBtn->getRect().mBottom;
00425                         handled = mJumpNextArrowBtn->handleMouseUp(local_x,     local_y, mask);
00426                 }
00427                 else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
00428                 {
00429                         S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
00430                         S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
00431                         handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
00432                 }
00433                 else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
00434                 {
00435                         S32 local_x = x - mNextArrowBtn->getRect().mLeft;
00436                         S32 local_y = y - mNextArrowBtn->getRect().mBottom;
00437                         handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask);
00438                 }
00439         }
00440         if (!handled)
00441         {
00442                 handled = LLPanel::handleMouseUp( x, y, mask );
00443         }
00444 
00445         commitHoveredButton(x, y);
00446         LLPanel* cur_panel = getCurrentPanel();
00447         if (hasMouseCapture())
00448         {
00449                 if (cur_panel)
00450                 {
00451                         if (!cur_panel->focusFirstItem(FALSE))
00452                         {
00453                                 // if nothing in the panel gets focus, make sure the new tab does
00454                                 // otherwise the last tab might keep focus
00455                                 getTab(getCurrentPanelIndex())->mButton->setFocus(TRUE);
00456                         }
00457                 }
00458                 gFocusMgr.setMouseCapture(NULL);
00459         }
00460         return handled;
00461 }
00462 
00463 // virtual
00464 BOOL LLTabContainer::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect )
00465 {
00466         BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect );
00467         if (!handled && getTabCount() > 0) 
00468         {
00469                 LLTabTuple* firsttuple = getTab(0);
00470 
00471                 BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
00472                 LLRect clip;
00473                 if (mIsVertical)
00474                 {
00475                         clip = LLRect(firsttuple->mButton->getRect().mLeft,
00476                                                   has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD : mPrevArrowBtn->getRect().mTop,
00477                                                   firsttuple->mButton->getRect().mRight,
00478                                                   has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD : mNextArrowBtn->getRect().mBottom );
00479                 }
00480                 else
00481                 {
00482                         clip = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft,
00483                                                   firsttuple->mButton->getRect().mTop,
00484                                                   has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight,
00485                                                   firsttuple->mButton->getRect().mBottom );
00486                 }
00487 
00488                 if( clip.pointInRect( x, y ) )
00489                 {
00490                         for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00491                         {
00492                                 LLTabTuple* tuple = *iter;
00493                                 tuple->mButton->setVisible( TRUE );
00494                                 S32 local_x = x - tuple->mButton->getRect().mLeft;
00495                                 S32 local_y = y - tuple->mButton->getRect().mBottom;
00496                                 handled = tuple->mButton->handleToolTip( local_x, local_y, msg, sticky_rect );
00497                                 if( handled )
00498                                 {
00499                                         break;
00500                                 }
00501                         }
00502                 }
00503 
00504                 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00505                 {
00506                         LLTabTuple* tuple = *iter;
00507                         tuple->mButton->setVisible( FALSE );
00508                 }
00509         }
00510         return handled;
00511 }
00512 
00513 // virtual
00514 BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask)
00515 {
00516         BOOL handled = FALSE;
00517         if (key == KEY_LEFT && mask == MASK_ALT)
00518         {
00519                 selectPrevTab();
00520                 handled = TRUE;
00521         }
00522         else if (key == KEY_RIGHT && mask == MASK_ALT)
00523         {
00524                 selectNextTab();
00525                 handled = TRUE;
00526         }
00527 
00528         if (handled)
00529         {
00530                 if (getCurrentPanel())
00531                 {
00532                         getCurrentPanel()->setFocus(TRUE);
00533                 }
00534         }
00535 
00536         if (!gFocusMgr.childHasKeyboardFocus(getCurrentPanel()))
00537         {
00538                 // if child has focus, but not the current panel, focus is on a button
00539                 if (mIsVertical)
00540                 {
00541                         switch(key)
00542                         {
00543                           case KEY_UP:
00544                                 selectPrevTab();
00545                                 handled = TRUE;
00546                                 break;
00547                           case KEY_DOWN:
00548                                 selectNextTab();
00549                                 handled = TRUE;
00550                                 break;
00551                           case KEY_LEFT:
00552                                 handled = TRUE;
00553                                 break;
00554                           case KEY_RIGHT:
00555                                 if (getTabPosition() == LEFT && getCurrentPanel())
00556                                 {
00557                                         getCurrentPanel()->setFocus(TRUE);
00558                                 }
00559                                 handled = TRUE;
00560                                 break;
00561                           default:
00562                                 break;
00563                         }
00564                 }
00565                 else
00566                 {
00567                         switch(key)
00568                         {
00569                           case KEY_UP:
00570                                 if (getTabPosition() == BOTTOM && getCurrentPanel())
00571                                 {
00572                                         getCurrentPanel()->setFocus(TRUE);
00573                                 }
00574                                 handled = TRUE;
00575                                 break;
00576                           case KEY_DOWN:
00577                                 if (getTabPosition() == TOP && getCurrentPanel())
00578                                 {
00579                                         getCurrentPanel()->setFocus(TRUE);
00580                                 }
00581                                 handled = TRUE;
00582                                 break;
00583                           case KEY_LEFT:
00584                                 selectPrevTab();
00585                                 handled = TRUE;
00586                                 break;
00587                           case KEY_RIGHT:
00588                                 selectNextTab();
00589                                 handled = TRUE;
00590                                 break;
00591                           default:
00592                                 break;
00593                         }
00594                 }
00595         }
00596         return handled;
00597 }
00598 
00599 // virtual
00600 LLXMLNodePtr LLTabContainer::getXML(bool save_children) const
00601 {
00602         LLXMLNodePtr node = LLPanel::getXML();
00603         node->createChild("tab_position", TRUE)->setStringValue((getTabPosition() == TOP ? "top" : "bottom"));
00604         return node;
00605 }
00606 
00607 // virtual
00608 BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,      EDragAndDropType type, void* cargo_data, EAcceptance *accept, LLString  &tooltip)
00609 {
00610         BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
00611 
00612         if( mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME )
00613         {
00614                 if (has_scroll_arrows)
00615                 {
00616                         if (mJumpPrevArrowBtn->getRect().pointInRect(x, y))
00617                         {
00618                                 S32     local_x = x     - mJumpPrevArrowBtn->getRect().mLeft;
00619                                 S32     local_y = y     - mJumpPrevArrowBtn->getRect().mBottom;
00620                                 mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
00621                         }
00622                         if (mJumpNextArrowBtn->getRect().pointInRect(x, y))
00623                         {
00624                                 S32     local_x = x     - mJumpNextArrowBtn->getRect().mLeft;
00625                                 S32     local_y = y     - mJumpNextArrowBtn->getRect().mBottom;
00626                                 mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
00627                         }
00628                         if (mPrevArrowBtn->getRect().pointInRect(x,     y))
00629                         {
00630                                 S32     local_x = x     - mPrevArrowBtn->getRect().mLeft;
00631                                 S32     local_y = y     - mPrevArrowBtn->getRect().mBottom;
00632                                 mPrevArrowBtn->handleHover(local_x,     local_y, mask);
00633                         }
00634                         else if (mNextArrowBtn->getRect().pointInRect(x, y))
00635                         {
00636                                 S32     local_x = x     - mNextArrowBtn->getRect().mLeft;
00637                                 S32     local_y = y     - mNextArrowBtn->getRect().mBottom;
00638                                 mNextArrowBtn->handleHover(local_x, local_y, mask);
00639                         }
00640                 }
00641 
00642                 for(tuple_list_t::iterator iter = mTabList.begin();     iter !=  mTabList.end(); ++iter)
00643                 {
00644                         LLTabTuple*     tuple = *iter;
00645                         tuple->mButton->setVisible(     TRUE );
00646                         S32     local_x = x     - tuple->mButton->getRect().mLeft;
00647                         S32     local_y = y     - tuple->mButton->getRect().mBottom;
00648                         if (tuple->mButton->pointInView(local_x, local_y) &&  tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
00649                         {
00650                                 tuple->mButton->onCommit();
00651                                 mDragAndDropDelayTimer.stop();
00652                         }
00653                 }
00654         }
00655 
00656         return LLView::handleDragAndDrop(x,     y, mask, drop, type, cargo_data,  accept, tooltip);
00657 }
00658 
00659 void LLTabContainer::addTabPanel(LLPanel* child, 
00660                                                                  const LLString& label, 
00661                                                                  BOOL select, 
00662                                                                  void (*on_tab_clicked)(void*, bool), 
00663                                                                  void* userdata,
00664                                                                  S32 indent,
00665                                                                  BOOL placeholder,
00666                                                                  eInsertionPoint insertion_point)
00667 {
00668         if (child->getParent() == this)
00669         {
00670                 // already a child of mine
00671                 return;
00672         }
00673         const LLFontGL* font = LLResMgr::getInstance()->getRes( mIsVertical ? LLFONT_SANSSERIF : LLFONT_SANSSERIF_SMALL );
00674 
00675         // Store the original label for possible xml export.
00676         child->setLabel(label);
00677         LLString trimmed_label = label;
00678         LLString::trim(trimmed_label);
00679 
00680         S32 button_width = mMinTabWidth;
00681         if (!mIsVertical)
00682         {
00683                 button_width = llclamp(font->getWidth(trimmed_label) + TAB_PADDING, mMinTabWidth, mMaxTabWidth);
00684         }
00685         
00686         // Tab panel
00687         S32 tab_panel_top;
00688         S32 tab_panel_bottom;
00689         if( getTabPosition() == LLTabContainer::TOP )
00690         {
00691                 S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT;
00692                 tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP);     
00693                 tab_panel_bottom = LLPANEL_BORDER_WIDTH;
00694         }
00695         else
00696         {
00697                 tab_panel_top = getRect().getHeight() - getTopBorderHeight();
00698                 tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP);  // Run to the edge, covering up the border
00699         }
00700         
00701         LLRect tab_panel_rect;
00702         if (mIsVertical)
00703         {
00704                 tab_panel_rect = LLRect(mMinTabWidth + (LLPANEL_BORDER_WIDTH * 2) + TABCNTRV_PAD, 
00705                                                                 getRect().getHeight() - LLPANEL_BORDER_WIDTH,
00706                                                                 getRect().getWidth() - LLPANEL_BORDER_WIDTH,
00707                                                                 LLPANEL_BORDER_WIDTH);
00708         }
00709         else
00710         {
00711                 tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH, 
00712                                                                 tab_panel_top,
00713                                                                 getRect().getWidth()-LLPANEL_BORDER_WIDTH,
00714                                                                 tab_panel_bottom );
00715         }
00716         child->setFollowsAll();
00717         child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
00718         child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
00719         // add this child later
00720 
00721         child->setVisible( FALSE );  // Will be made visible when selected
00722 
00723         mTotalTabWidth += button_width;
00724 
00725         // Tab button
00726         LLRect btn_rect;  // Note: btn_rect.mLeft is just a dummy.  Will be updated in draw().
00727         LLString tab_img;
00728         LLString tab_selected_img;
00729         S32 tab_fudge = 1;              //  To make new tab art look better, nudge buttons up 1 pel
00730 
00731         if (mIsVertical)
00732         {
00733                 btn_rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2,     // JC - Fudge factor
00734                                                                    (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * getTabCount()),
00735                                                                    mMinTabWidth,
00736                                                                    BTN_HEIGHT);
00737         }
00738         else if( getTabPosition() == LLTabContainer::TOP )
00739         {
00740                 btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
00741                 tab_img = "tab_top_blue.tga";
00742                 tab_selected_img = "tab_top_selected_blue.tga";
00743         }
00744         else
00745         {
00746                 btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
00747                 tab_img = "tab_bottom_blue.tga";
00748                 tab_selected_img = "tab_bottom_selected_blue.tga";
00749         }
00750 
00751         LLTextBox* textbox = NULL;
00752         LLButton* btn = NULL;
00753         
00754         if (placeholder)
00755         {
00756                 btn_rect.translate(0, -LLBUTTON_V_PAD-2);
00757                 textbox = new LLTextBox(trimmed_label, btn_rect, trimmed_label, font);
00758                 
00759                 btn = new LLButton("", LLRect(0,0,0,0));
00760         }
00761         else
00762         {
00763                 if (mIsVertical)
00764                 {
00765                         btn = new LLButton("vert tab button",
00766                                                            btn_rect,
00767                                                            "",
00768                                                            "", 
00769                                                            "", 
00770                                                            &LLTabContainer::onTabBtn, NULL,
00771                                                            font,
00772                                                            trimmed_label, trimmed_label);
00773                         btn->setImages("tab_left.tga", "tab_left_selected.tga");
00774                         btn->setScaleImage(TRUE);
00775                         btn->setHAlign(LLFontGL::LEFT);
00776                         btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
00777                         btn->setTabStop(FALSE);
00778                         if (indent)
00779                         {
00780                                 btn->setLeftHPad(indent);
00781                         }
00782                 }
00783                 else
00784                 {
00785                         LLString tooltip = trimmed_label;
00786                         tooltip += "\nAlt-Left arrow for previous tab";
00787                         tooltip += "\nAlt-Right arrow for next tab";
00788 
00789                         btn = new LLButton(LLString(child->getName()) + " tab",
00790                                                            btn_rect, 
00791                                                            "", "", "",
00792                                                            &LLTabContainer::onTabBtn, NULL, // set userdata below
00793                                                            font,
00794                                                            trimmed_label, trimmed_label );
00795                         btn->setVisible( FALSE );
00796                         btn->setToolTip( tooltip );
00797                         btn->setScaleImage(TRUE);
00798                         btn->setImages(tab_img, tab_selected_img);
00799 
00800                         // Try to squeeze in a bit more text
00801                         btn->setLeftHPad( 4 );
00802                         btn->setRightHPad( 2 );
00803                         btn->setHAlign(LLFontGL::LEFT);
00804                         btn->setTabStop(FALSE);
00805                         if (indent)
00806                         {
00807                                 btn->setLeftHPad(indent);
00808                         }
00809 
00810                         if( getTabPosition() == TOP )
00811                         {
00812                                 btn->setFollowsTop();
00813                         }
00814                         else
00815                         {
00816                                 btn->setFollowsBottom();
00817                         }
00818                 }
00819         }
00820         
00821         LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, textbox );
00822         insertTuple( tuple, insertion_point );
00823 
00824         if (textbox)
00825         {
00826                 textbox->setSaveToXML(false);
00827                 addChild( textbox, 0 );
00828         }
00829         if (btn)
00830         {
00831                 btn->setSaveToXML(false);
00832                 btn->setCallbackUserData( tuple );
00833                 addChild( btn, 0 );
00834         }
00835         if (child)
00836         {
00837                 addChild(child, 1);
00838         }
00839         
00840         if( select )
00841         {
00842                 selectLastTab();
00843         }
00844 
00845         updateMaxScrollPos();
00846 }
00847 
00848 void LLTabContainer::addPlaceholder(LLPanel* child, const LLString& label)
00849 {
00850         addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE);
00851 }
00852 
00853 void LLTabContainer::removeTabPanel(LLPanel* child)
00854 {
00855         if (mIsVertical)
00856         {
00857                 // Fix-up button sizes
00858                 S32 tab_count = 0;
00859                 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00860                 {
00861                         LLTabTuple* tuple = *iter;
00862                         LLRect rect;
00863                         rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
00864                                                                    (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * (tab_count)),
00865                                                                    mMinTabWidth,
00866                                                                    BTN_HEIGHT);
00867                         if (tuple->mPlaceholderText)
00868                         {
00869                                 tuple->mPlaceholderText->setRect(rect);
00870                         }
00871                         else
00872                         {
00873                                 tuple->mButton->setRect(rect);
00874                         }
00875                         tab_count++;
00876                 }
00877         }
00878         else
00879         {
00880                 // Adjust the total tab width.
00881                 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00882                 {
00883                         LLTabTuple* tuple = *iter;
00884                         if( tuple->mTabPanel == child )
00885                         {
00886                                 mTotalTabWidth -= tuple->mButton->getRect().getWidth();
00887                                 break;
00888                         }
00889                 }
00890         }
00891         
00892         BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this);
00893 
00894         // If the tab being deleted is the selected one, select a different tab.
00895         for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00896         {
00897                 LLTabTuple* tuple = *iter;
00898                 if( tuple->mTabPanel == child )
00899                 {
00900                         removeChild( tuple->mButton );
00901                         delete tuple->mButton;
00902 
00903                         removeChild( tuple->mTabPanel );
00904 //                      delete tuple->mTabPanel;
00905                         
00906                         mTabList.erase( iter );
00907                         delete tuple;
00908 
00909                         break;
00910                 }
00911         }
00912 
00913         // make sure we don't have more locked tabs than we have tabs
00914         mLockedTabCount = llmin(getTabCount(), mLockedTabCount);
00915 
00916         if (mCurrentTabIdx >= (S32)mTabList.size())
00917         {
00918                 mCurrentTabIdx = mTabList.size()-1;
00919         }
00920         selectTab(mCurrentTabIdx);
00921         if (has_focus)
00922         {
00923                 LLPanel* panelp = getPanelByIndex(mCurrentTabIdx);
00924                 if (panelp)
00925                 {
00926                         panelp->setFocus(TRUE);
00927                 }
00928         }
00929 
00930         updateMaxScrollPos();
00931 }
00932 
00933 void LLTabContainer::lockTabs(S32 num_tabs)
00934 {
00935         // count current tabs or use supplied value and ensure no new tabs get
00936         // inserted between them
00937         mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount();
00938 }
00939 
00940 void LLTabContainer::unlockTabs()
00941 {
00942         mLockedTabCount = 0;
00943 }
00944 
00945 void LLTabContainer::enableTabButton(S32 which, BOOL enable)
00946 {
00947         if (which >= 0 && which < (S32)mTabList.size())
00948         {
00949                 mTabList[which]->mButton->setEnabled(enable);
00950         }
00951 }
00952 
00953 void LLTabContainer::deleteAllTabs()
00954 {
00955         // Remove all the tab buttons and delete them.  Also, unlink all the child panels.
00956         for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00957         {
00958                 LLTabTuple* tuple = *iter;
00959 
00960                 removeChild( tuple->mButton );
00961                 delete tuple->mButton;
00962 
00963                 removeChild( tuple->mTabPanel );
00964 //              delete tuple->mTabPanel;
00965         }
00966 
00967         // Actually delete the tuples themselves
00968         std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
00969         mTabList.clear();
00970         
00971         // And there isn't a current tab any more
00972         mCurrentTabIdx = -1;
00973 }
00974 
00975 LLPanel* LLTabContainer::getCurrentPanel()
00976 {
00977         if (mCurrentTabIdx >= 0 && mCurrentTabIdx < (S32) mTabList.size())
00978         {
00979                 return mTabList[mCurrentTabIdx]->mTabPanel;
00980         }
00981         return NULL;
00982 }
00983 
00984 S32 LLTabContainer::getCurrentPanelIndex()
00985 {
00986         return mCurrentTabIdx;
00987 }
00988 
00989 S32 LLTabContainer::getTabCount()
00990 {
00991         return mTabList.size();
00992 }
00993 
00994 LLPanel* LLTabContainer::getPanelByIndex(S32 index)
00995 {
00996         if (index >= 0 && index < (S32)mTabList.size())
00997         {
00998                 return mTabList[index]->mTabPanel;
00999         }
01000         return NULL;
01001 }
01002 
01003 S32 LLTabContainer::getIndexForPanel(LLPanel* panel)
01004 {
01005         for (S32 index = 0; index < (S32)mTabList.size(); index++)
01006         {
01007                 if (mTabList[index]->mTabPanel == panel)
01008                 {
01009                         return index;
01010                 }
01011         }
01012         return -1;
01013 }
01014 
01015 S32 LLTabContainer::getPanelIndexByTitle(const LLString& title)
01016 {
01017         for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
01018         {
01019                 if (title == mTabList[index]->mButton->getLabelSelected())
01020                 {
01021                         return index;
01022                 }
01023         }
01024         return -1;
01025 }
01026 
01027 LLPanel *LLTabContainer::getPanelByName(const LLString& name)
01028 {
01029         for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
01030         {
01031                 LLPanel *panel = mTabList[index]->mTabPanel;
01032                 if (name == panel->getName())
01033                 {
01034                         return panel;
01035                 }
01036         }
01037         return NULL;
01038 }
01039 
01040 // Change the name of the button for the current tab.
01041 void LLTabContainer::setCurrentTabName(const LLString& name)
01042 {
01043         // Might not have a tab selected
01044         if (mCurrentTabIdx < 0) return;
01045 
01046         mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name);
01047         mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name);
01048 }
01049 
01050 void LLTabContainer::selectFirstTab()
01051 {
01052         selectTab( 0 );
01053 }
01054 
01055 
01056 void LLTabContainer::selectLastTab()
01057 {
01058         selectTab( mTabList.size()-1 );
01059 }
01060 
01061 void LLTabContainer::selectNextTab()
01062 {
01063         BOOL tab_has_focus = FALSE;
01064         if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
01065         {
01066                 tab_has_focus = TRUE;
01067         }
01068         S32 idx = mCurrentTabIdx+1;
01069         if (idx >= (S32)mTabList.size())
01070                 idx = 0;
01071         while (!selectTab(idx) && idx != mCurrentTabIdx)
01072         {
01073                 idx = (idx + 1 ) % (S32)mTabList.size();
01074         }
01075 
01076         if (tab_has_focus)
01077         {
01078                 mTabList[idx]->mButton->setFocus(TRUE);
01079         }
01080 }
01081 
01082 void LLTabContainer::selectPrevTab()
01083 {
01084         BOOL tab_has_focus = FALSE;
01085         if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
01086         {
01087                 tab_has_focus = TRUE;
01088         }
01089         S32 idx = mCurrentTabIdx-1;
01090         if (idx < 0)
01091                 idx = mTabList.size()-1;
01092         while (!selectTab(idx) && idx != mCurrentTabIdx)
01093         {
01094                 idx = idx - 1;
01095                 if (idx < 0)
01096                         idx = mTabList.size()-1;
01097         }
01098         if (tab_has_focus)
01099         {
01100                 mTabList[idx]->mButton->setFocus(TRUE);
01101         }
01102 }       
01103 
01104 BOOL LLTabContainer::selectTabPanel(LLPanel* child)
01105 {
01106         S32 idx = 0;
01107         for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
01108         {
01109                 LLTabTuple* tuple = *iter;
01110                 if( tuple->mTabPanel == child )
01111                 {
01112                         return selectTab( idx );
01113                 }
01114                 idx++;
01115         }
01116         return FALSE;
01117 }
01118 
01119 BOOL LLTabContainer::selectTab(S32 which)
01120 {
01121         if (which >= getTabCount()) return FALSE;
01122         if (which < 0) return FALSE;
01123 
01124         //if( gFocusMgr.childHasKeyboardFocus( this ) )
01125         //{
01126         //      gFocusMgr.setKeyboardFocus( NULL );
01127         //}
01128 
01129         LLTabTuple* selected_tuple = getTab(which);
01130         if (!selected_tuple)
01131         {
01132                 return FALSE;
01133         }
01134         
01135         BOOL is_visible = FALSE;
01136         if (getTab(which)->mButton->getEnabled())
01137         {
01138                 setCurrentPanelIndex(which);
01139 
01140                 S32 i = 0;
01141                 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
01142                 {
01143                         LLTabTuple* tuple = *iter;
01144                         BOOL is_selected = ( tuple == selected_tuple );
01145                         tuple->mTabPanel->setVisible( is_selected );
01146 //                      tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here.
01147                         tuple->mButton->setToggleState( is_selected );
01148                         // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs
01149                         tuple->mButton->setTabStop( is_selected );
01150                         
01151                         if( is_selected && (mIsVertical || (getMaxScrollPos() > 0)))
01152                         {
01153                                 // Make sure selected tab is within scroll region
01154                                 if (mIsVertical)
01155                                 {
01156                                         S32 num_visible = getTabCount() - getMaxScrollPos();
01157                                         if( i >= getScrollPos() && i <= getScrollPos() + num_visible)
01158                                         {
01159                                                 setCurrentPanelIndex(which);
01160                                                 is_visible = TRUE;
01161                                         }
01162                                         else
01163                                         {
01164                                                 is_visible = FALSE;
01165                                         }
01166                                 }
01167                                 else
01168                                 {
01169                                         if( i < getScrollPos() )
01170                                         {
01171                                                 setScrollPos(i);
01172                                         }
01173                                         else
01174                                         {
01175                                                 S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
01176                                                 S32 running_tab_width = tuple->mButton->getRect().getWidth();
01177                                                 S32 j = i - 1;
01178                                                 S32 min_scroll_pos = i;
01179                                                 if (running_tab_width < available_width_with_arrows)
01180                                                 {
01181                                                         while (j >= 0)
01182                                                         {
01183                                                                 LLTabTuple* other_tuple = getTab(j);
01184                                                                 running_tab_width += other_tuple->mButton->getRect().getWidth();
01185                                                                 if (running_tab_width > available_width_with_arrows)
01186                                                                 {
01187                                                                         break;
01188                                                                 }
01189                                                                 j--;
01190                                                         }
01191                                                         min_scroll_pos = j + 1;
01192                                                 }
01193                                                 setScrollPos(llclamp(getScrollPos(), min_scroll_pos, i));
01194                                                 setScrollPos(llmin(getScrollPos(), getMaxScrollPos()));
01195                                         }
01196                                         is_visible = TRUE;
01197                                 }
01198                         }
01199                         i++;
01200                 }
01201                 if( selected_tuple->mOnChangeCallback )
01202                 {
01203                         selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false );
01204                 }
01205         }
01206         if (mIsVertical && getCurrentPanelIndex() >= 0)
01207         {
01208                 LLTabTuple* tuple = getTab(getCurrentPanelIndex());
01209                 tuple->mTabPanel->setVisible( TRUE );
01210                 tuple->mButton->setToggleState( TRUE );
01211         }
01212         return is_visible;
01213 }
01214 
01215 BOOL LLTabContainer::selectTabByName(const LLString& name)
01216 {
01217         LLPanel* panel = getPanelByName(name);
01218         if (!panel)
01219         {
01220                 llwarns << "LLTabContainer::selectTabByName("
01221                         << name << ") failed" << llendl;
01222                 return FALSE;
01223         }
01224 
01225         BOOL result = selectTabPanel(panel);
01226         return result;
01227 }
01228 
01229 BOOL LLTabContainer::getTabPanelFlashing(LLPanel *child)
01230 {
01231         LLTabTuple* tuple = getTabByPanel(child);
01232         if( tuple )
01233         {
01234                 return tuple->mButton->getFlashing();
01235         }
01236         return FALSE;
01237 }
01238 
01239 void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state )
01240 {
01241         LLTabTuple* tuple = getTabByPanel(child);
01242         if( tuple )
01243         {
01244                 tuple->mButton->setFlashing( state );
01245         }
01246 }
01247 
01248 void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color)
01249 {
01250         LLTabTuple* tuple = getTabByPanel(child);
01251         if( tuple )
01252         {
01253                 tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT, color);
01254 
01255                 if (!mIsVertical)
01256                 {
01257                         const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
01258                         // remove current width from total tab strip width
01259                         mTotalTabWidth -= tuple->mButton->getRect().getWidth();
01260 
01261                         S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? 
01262                                 tuple->mButton->getImageOverlay()->getImage()->getWidth(0) :
01263                                 0;
01264 
01265                         tuple->mPadding = image_overlay_width;
01266 
01267                         tuple->mButton->setRightHPad(6);
01268                         tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), 
01269                                                                         tuple->mButton->getRect().getHeight());
01270                         // add back in button width to total tab strip width
01271                         mTotalTabWidth += tuple->mButton->getRect().getWidth();
01272 
01273                         // tabs have changed size, might need to scroll to see current tab
01274                         updateMaxScrollPos();
01275                 }
01276         }
01277 }
01278 
01279 void LLTabContainer::setTitle(const LLString& title)
01280 {       
01281         if (mTitleBox)
01282         {
01283                 mTitleBox->setText( title );
01284         }
01285 }
01286 
01287 const LLString LLTabContainer::getPanelTitle(S32 index)
01288 {
01289         if (index >= 0 && index < (S32)mTabList.size())
01290         {
01291                 LLButton* tab_button = mTabList[index]->mButton;
01292                 return tab_button->getLabelSelected();
01293         }
01294         return LLString::null;
01295 }
01296 
01297 void LLTabContainer::setTopBorderHeight(S32 height)
01298 {
01299         mTopBorderHeight = height;
01300 }
01301 
01302 S32 LLTabContainer::getTopBorderHeight() const
01303 {
01304         return mTopBorderHeight;
01305 }
01306 
01307 void LLTabContainer::setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*, bool))
01308 {
01309         LLTabTuple* tuplep = getTabByPanel(tab);
01310         if (tuplep)
01311         {
01312                 tuplep->mOnChangeCallback = on_tab_clicked;
01313         }
01314 }
01315 
01316 void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata)
01317 {
01318         LLTabTuple* tuplep = getTabByPanel(tab);
01319         if (tuplep)
01320         {
01321                 tuplep->mUserData = userdata;
01322         }
01323 }
01324 
01325 void LLTabContainer::setRightTabBtnOffset(S32 offset)
01326 {
01327         mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 );
01328         mRightTabBtnOffset = offset;
01329         updateMaxScrollPos();
01330 }
01331 
01332 void LLTabContainer::setPanelTitle(S32 index, const LLString& title)
01333 {
01334         if (index >= 0 && index < getTabCount())
01335         {
01336                 LLTabTuple* tuple = getTab(index);
01337                 LLButton* tab_button = tuple->mButton;
01338                 const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
01339                 mTotalTabWidth -= tab_button->getRect().getWidth();
01340                 tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight());
01341                 mTotalTabWidth += tab_button->getRect().getWidth();
01342                 tab_button->setLabelSelected(title);
01343                 tab_button->setLabelUnselected(title);
01344         }
01345         updateMaxScrollPos();
01346 }
01347 
01348 
01349 // static 
01350 void LLTabContainer::onTabBtn( void* userdata )
01351 {
01352         LLTabTuple* tuple = (LLTabTuple*) userdata;
01353         LLTabContainer* self = tuple->mTabContainer;
01354         self->selectTabPanel( tuple->mTabPanel );
01355         
01356         if( tuple->mOnChangeCallback )
01357         {
01358                 tuple->mOnChangeCallback( tuple->mUserData, true );
01359         }
01360 
01361         tuple->mTabPanel->setFocus(TRUE);
01362 }
01363 
01364 // static 
01365 void LLTabContainer::onCloseBtn( void* userdata )
01366 {
01367         LLTabContainer* self = (LLTabContainer*) userdata;
01368         if( self->mCloseCallback )
01369         {
01370                 self->mCloseCallback( self->mCallbackUserdata );
01371         }
01372 }
01373 
01374 // static 
01375 void LLTabContainer::onNextBtn( void* userdata )
01376 {
01377         // Scroll tabs to the left
01378         LLTabContainer* self = (LLTabContainer*) userdata;
01379         if (!self->mScrolled)
01380         {
01381                 self->scrollNext();
01382         }
01383         self->mScrolled = FALSE;
01384 }
01385 
01386 // static 
01387 void LLTabContainer::onNextBtnHeld( void* userdata )
01388 {
01389         LLTabContainer* self = (LLTabContainer*) userdata;
01390         if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
01391         {
01392                 self->mScrollTimer.reset();
01393                 self->scrollNext();
01394                 self->mScrolled = TRUE;
01395         }
01396 }
01397 
01398 // static 
01399 void LLTabContainer::onPrevBtn( void* userdata )
01400 {
01401         LLTabContainer* self = (LLTabContainer*) userdata;
01402         if (!self->mScrolled)
01403         {
01404                 self->scrollPrev();
01405         }
01406         self->mScrolled = FALSE;
01407 }
01408 
01409 // static 
01410 void LLTabContainer::onJumpFirstBtn( void* userdata )
01411 {
01412         LLTabContainer* self = (LLTabContainer*) userdata;
01413         self->mScrollPos = 0;
01414 }
01415 
01416 // static 
01417 void LLTabContainer::onJumpLastBtn( void* userdata )
01418 {
01419         LLTabContainer* self = (LLTabContainer*) userdata;
01420         self->mScrollPos = self->mMaxScrollPos;
01421 }
01422 
01423 // static 
01424 void LLTabContainer::onPrevBtnHeld( void* userdata )
01425 {
01426         LLTabContainer* self = (LLTabContainer*) userdata;
01427         if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
01428         {
01429                 self->mScrollTimer.reset();
01430                 self->scrollPrev();
01431                 self->mScrolled = TRUE;
01432         }
01433 }
01434 
01435 // static
01436 LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
01437 {
01438         LLString name("tab_container");
01439         node->getAttributeString("name", name);
01440 
01441         // Figure out if we are creating a vertical or horizontal tab container.
01442         bool is_vertical = false;
01443         LLTabContainer::TabPosition tab_position = LLTabContainer::TOP;
01444         if (node->hasAttribute("tab_position"))
01445         {
01446                 LLString tab_position_string;
01447                 node->getAttributeString("tab_position", tab_position_string);
01448                 LLString::toLower(tab_position_string);
01449 
01450                 if ("top" == tab_position_string)
01451                 {
01452                         tab_position = LLTabContainer::TOP;
01453                         is_vertical = false;
01454                 }
01455                 else if ("bottom" == tab_position_string)
01456                 {
01457                         tab_position = LLTabContainer::BOTTOM;
01458                         is_vertical = false;
01459                 }
01460                 else if ("left" == tab_position_string)
01461                 {
01462                         is_vertical = true;
01463                 }
01464         }
01465         BOOL border = FALSE;
01466         node->getAttributeBOOL("border", border);
01467 
01468         LLTabContainer* tab_container = new LLTabContainer(name, LLRect::null, tab_position, border, is_vertical);
01469         
01470         S32 tab_min_width = tab_container->mMinTabWidth;
01471         if (node->hasAttribute("tab_width"))
01472         {
01473                 node->getAttributeS32("tab_width", tab_min_width);
01474         }
01475         else if( node->hasAttribute("tab_min_width"))
01476         {
01477                 node->getAttributeS32("tab_min_width", tab_min_width);
01478         }
01479 
01480         S32     tab_max_width = tab_container->mMaxTabWidth;
01481         if (node->hasAttribute("tab_max_width"))
01482         {
01483                 node->getAttributeS32("tab_max_width", tab_max_width);
01484         }
01485 
01486         tab_container->setMinTabWidth(tab_min_width); 
01487         tab_container->setMaxTabWidth(tab_max_width); 
01488         
01489         BOOL hidden(tab_container->getTabsHidden());
01490         node->getAttributeBOOL("hide_tabs", hidden);
01491         tab_container->setTabsHidden(hidden);
01492 
01493         tab_container->setPanelParameters(node, parent);
01494 
01495         if (LLFloater::getFloaterHost())
01496         {
01497                 LLFloater::getFloaterHost()->setTabContainer(tab_container);
01498         }
01499 
01500         //parent->addChild(tab_container);
01501 
01502         // Add all tab panels.
01503         LLXMLNodePtr child;
01504         for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
01505         {
01506                 LLView *control = factory->createCtrlWidget(tab_container, child);
01507                 if (control && control->isPanel())
01508                 {
01509                         LLPanel* panelp = (LLPanel*)control;
01510                         LLString label;
01511                         child->getAttributeString("label", label);
01512                         if (label.empty())
01513                         {
01514                                 label = panelp->getLabel();
01515                         }
01516                         BOOL placeholder = FALSE;
01517                         child->getAttributeBOOL("placeholder", placeholder);
01518                         tab_container->addTabPanel(panelp, label.c_str(), false,
01519                                                                            NULL, NULL, 0, placeholder);
01520                 }
01521         }
01522 
01523         tab_container->selectFirstTab();
01524 
01525         tab_container->postBuild();
01526 
01527         tab_container->initButtons(); // now that we have the correct rect
01528         
01529         return tab_container;
01530 }
01531 
01532 // private
01533 
01534 void LLTabContainer::initButtons()
01535 {
01536         // Hack:
01537         if (getRect().getHeight() == 0 || mPrevArrowBtn)
01538         {
01539                 return; // Don't have a rect yet or already got called
01540         }
01541         
01542         LLString out_id;
01543         LLString in_id;
01544 
01545         if (mIsVertical)
01546         {
01547                 // Left and right scroll arrows (for when there are too many tabs to show all at once).
01548                 S32 btn_top = getRect().getHeight();
01549                 S32 btn_top_lower = getRect().mBottom+TABCNTRV_ARROW_BTN_SIZE;
01550 
01551                 LLRect up_arrow_btn_rect;
01552                 up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );
01553 
01554                 LLRect down_arrow_btn_rect;
01555                 down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );
01556 
01557                 out_id = "UIImgBtnScrollUpOutUUID";
01558                 in_id = "UIImgBtnScrollUpInUUID";
01559                 mPrevArrowBtn = new LLButton("Up Arrow", up_arrow_btn_rect,
01560                                                                          out_id, in_id, "",
01561                                                                          &onPrevBtn, this, NULL );
01562                 mPrevArrowBtn->setFollowsTop();
01563                 mPrevArrowBtn->setFollowsLeft();
01564 
01565                 out_id = "UIImgBtnScrollDownOutUUID";
01566                 in_id = "UIImgBtnScrollDownInUUID";
01567                 mNextArrowBtn = new LLButton("Down Arrow", down_arrow_btn_rect,
01568                                                                          out_id, in_id, "",
01569                                                                          &onNextBtn, this, NULL );
01570                 mNextArrowBtn->setFollowsBottom();
01571                 mNextArrowBtn->setFollowsLeft();
01572         }
01573         else // Horizontal
01574         {
01575                 S32 arrow_fudge = 1;            //  match new art better 
01576 
01577                 // tabs on bottom reserve room for resize handle (just in case)
01578                 if (getTabPosition() == BOTTOM)
01579                 {
01580                         mRightTabBtnOffset = RESIZE_HANDLE_WIDTH;
01581                 }
01582 
01583                 // Left and right scroll arrows (for when there are too many tabs to show all at once).
01584                 S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : TABCNTR_ARROW_BTN_SIZE + 1;
01585 
01586                 LLRect left_arrow_btn_rect;
01587                 left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+TABCNTR_ARROW_BTN_SIZE, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
01588 
01589                 LLRect jump_left_arrow_btn_rect;
01590                 jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
01591 
01592                 S32 right_pad = TABCNTR_ARROW_BTN_SIZE + LLPANEL_BORDER_WIDTH + 1;
01593 
01594                 LLRect right_arrow_btn_rect;
01595                 right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - TABCNTR_ARROW_BTN_SIZE,
01596                                                                                                 btn_top + arrow_fudge,
01597                                                                                                 TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
01598 
01599 
01600                 LLRect jump_right_arrow_btn_rect;
01601                 jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad,
01602                                                                                                          btn_top + arrow_fudge,
01603                                                                                                          TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
01604 
01605                 out_id = "UIImgBtnJumpLeftOutUUID";
01606                 in_id = "UIImgBtnJumpLeftInUUID";
01607                 mJumpPrevArrowBtn = new LLButton("Jump Left Arrow", jump_left_arrow_btn_rect,
01608                                                                                  out_id, in_id, "",
01609                                                                                  &LLTabContainer::onJumpFirstBtn, this, LLFontGL::sSansSerif );
01610                 mJumpPrevArrowBtn->setFollowsLeft();
01611 
01612                 out_id = "UIImgBtnScrollLeftOutUUID";
01613                 in_id = "UIImgBtnScrollLeftInUUID";
01614                 mPrevArrowBtn = new LLButton("Left Arrow", left_arrow_btn_rect,
01615                                                                          out_id, in_id, "",
01616                                                                          &LLTabContainer::onPrevBtn, this, LLFontGL::sSansSerif );
01617                 mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld);
01618                 mPrevArrowBtn->setFollowsLeft();
01619         
01620                 out_id = "UIImgBtnJumpRightOutUUID";
01621                 in_id = "UIImgBtnJumpRightInUUID";
01622                 mJumpNextArrowBtn = new LLButton("Jump Right Arrow", jump_right_arrow_btn_rect,
01623                                                                                  out_id, in_id, "",
01624                                                                                  &LLTabContainer::onJumpLastBtn, this,
01625                                                                                  LLFontGL::sSansSerif);
01626                 mJumpNextArrowBtn->setFollowsRight();
01627 
01628                 out_id = "UIImgBtnScrollRightOutUUID";
01629                 in_id = "UIImgBtnScrollRightInUUID";
01630                 mNextArrowBtn = new LLButton("Right Arrow", right_arrow_btn_rect,
01631                                                                          out_id, in_id, "",
01632                                                                          &LLTabContainer::onNextBtn, this,
01633                                                                          LLFontGL::sSansSerif);
01634                 mNextArrowBtn->setFollowsRight();
01635 
01636                 if( getTabPosition() == TOP )
01637                 {
01638                         mNextArrowBtn->setFollowsTop();
01639                         mPrevArrowBtn->setFollowsTop();
01640                         mJumpPrevArrowBtn->setFollowsTop();
01641                         mJumpNextArrowBtn->setFollowsTop();
01642                 }
01643                 else
01644                 {
01645                         mNextArrowBtn->setFollowsBottom();
01646                         mPrevArrowBtn->setFollowsBottom();
01647                         mJumpPrevArrowBtn->setFollowsBottom();
01648                         mJumpNextArrowBtn->setFollowsBottom();
01649                 }
01650         }
01651 
01652         mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld);
01653         mPrevArrowBtn->setSaveToXML(false);
01654         mPrevArrowBtn->setTabStop(FALSE);
01655         addChild(mPrevArrowBtn);
01656 
01657         mNextArrowBtn->setHeldDownCallback(onNextBtnHeld);
01658         mNextArrowBtn->setSaveToXML(false);
01659         mNextArrowBtn->setTabStop(FALSE);
01660         addChild(mNextArrowBtn);
01661 
01662         if (mJumpPrevArrowBtn)
01663         {
01664                 mJumpPrevArrowBtn->setSaveToXML(false);
01665                 mJumpPrevArrowBtn->setTabStop(FALSE);
01666                 addChild(mJumpPrevArrowBtn);
01667         }
01668 
01669         if (mJumpNextArrowBtn)
01670         {
01671                 mJumpNextArrowBtn->setSaveToXML(false);
01672                 mJumpNextArrowBtn->setTabStop(FALSE);
01673                 addChild(mJumpNextArrowBtn);
01674         }
01675         
01676         // set default tab group to be panel contents
01677         setDefaultTabGroup(1);
01678 }
01679 
01680 LLTabContainer::LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child)
01681 {
01682         for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
01683         {
01684                 LLTabTuple* tuple = *iter;
01685                 if( tuple->mTabPanel == child )
01686                 {
01687                         return tuple;
01688                 }
01689         }
01690         return NULL;
01691 }
01692 
01693 void LLTabContainer::insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point)
01694 {
01695         switch(insertion_point)
01696         {
01697         case START:
01698                 // insert the new tab in the front of the list
01699                 mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
01700                 break;
01701         case LEFT_OF_CURRENT:
01702                 // insert the new tab before the current tab (but not before mLockedTabCount)
01703                 {
01704                 tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx);
01705                 mTabList.insert(current_iter, tuple);
01706                 }
01707                 break;
01708 
01709         case RIGHT_OF_CURRENT:
01710                 // insert the new tab after the current tab (but not before mLockedTabCount)
01711                 {
01712                 tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1);
01713                 mTabList.insert(current_iter, tuple);
01714                 }
01715                 break;
01716         case END:
01717         default:
01718                 mTabList.push_back( tuple );
01719         }
01720 }
01721 
01722 
01723 
01724 void LLTabContainer::updateMaxScrollPos()
01725 {
01726         BOOL no_scroll = TRUE;
01727         if (mIsVertical)
01728         {
01729                 S32 tab_total_height = (BTN_HEIGHT + TABCNTRV_PAD) * getTabCount();
01730                 S32 available_height = getRect().getHeight() - getTopBorderHeight();
01731                 if( tab_total_height > available_height )
01732                 {
01733                         S32 available_height_with_arrows = getRect().getHeight() - 2*(TABCNTRV_ARROW_BTN_SIZE + 3*TABCNTRV_PAD);
01734                         S32 additional_needed = tab_total_height - available_height_with_arrows;
01735                         setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) );
01736                         no_scroll = FALSE;
01737                 }
01738         }
01739         else
01740         {
01741                 S32 tab_space = 0;
01742                 S32 available_space = 0;
01743                 tab_space = mTotalTabWidth;
01744                 available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_TAB_H_PAD);
01745 
01746                 if( tab_space > available_space )
01747                 {
01748                         S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
01749                         // subtract off reserved portion on left
01750                         available_width_with_arrows -= TABCNTR_TAB_PARTIAL_WIDTH;
01751 
01752                         S32 running_tab_width = 0;
01753                         setMaxScrollPos(getTabCount());
01754                         for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it)
01755                         {
01756                                 running_tab_width += (*tab_it)->mButton->getRect().getWidth();
01757                                 if (running_tab_width > available_width_with_arrows)
01758                                 {
01759                                         break;
01760                                 }
01761                                 setMaxScrollPos(getMaxScrollPos()-1);
01762                         }
01763                         // in case last tab doesn't actually fit on screen, make it the last scrolling position
01764                         setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1));
01765                         no_scroll = FALSE;
01766                 }
01767         }
01768         if (no_scroll)
01769         {
01770                 setMaxScrollPos(0);
01771                 setScrollPos(0);
01772         }
01773         if (getScrollPos() > getMaxScrollPos())
01774         {
01775                 setScrollPos(getMaxScrollPos()); // maybe just enforce this via limits in setScrollPos instead?
01776         }
01777 }
01778 
01779 void LLTabContainer::commitHoveredButton(S32 x, S32 y)
01780 {
01781         if (hasMouseCapture())
01782         {
01783                 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
01784                 {
01785                         LLTabTuple* tuple = *iter;
01786                         tuple->mButton->setVisible( TRUE );
01787                         S32 local_x = x - tuple->mButton->getRect().mLeft;
01788                         S32 local_y = y - tuple->mButton->getRect().mBottom;
01789                         if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
01790                         {
01791                                 tuple->mButton->onCommit();
01792                         }
01793                 }
01794         }
01795 }
01796 
01797 

Generated on Fri May 16 08:32:58 2008 for SecondLife by  doxygen 1.5.5