lltabcontainer.cpp

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

Generated on Thu Jul 1 06:09:15 2010 for Second Life Viewer by  doxygen 1.4.7