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;
00053 const S32 TABCNTR_TAB_HEIGHT = 16;
00054 const S32 TABCNTR_ARROW_BTN_SIZE = 16;
00055 const S32 TABCNTR_BUTTON_PANEL_OVERLAP = 1;
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
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
00091 mJumpPrevArrowBtn(NULL),
00092 mJumpNextArrowBtn(NULL),
00093 mRightTabBtnOffset(0),
00094 mTotalTabWidth(0)
00095 {
00096
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
00112 void LLTabContainer::setValue(const LLSD& value)
00113 {
00114 selectTab((S32) value.asInteger());
00115 }
00116
00117
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
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
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
00171 target_pixel_scroll -= TABCNTR_TAB_PARTIAL_WIDTH;
00172
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
00196 left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (TABCNTR_ARROW_BTN_SIZE * 2) : TABCNTR_TAB_H_PAD);
00197 left -= getScrollPosPixels();
00198 }
00199
00200
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
00210 if (!getTabsHidden())
00211 {
00212
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
00220 LLRect clip_rect = getLocalRect();
00221 if (has_scroll_arrows)
00222 {
00223
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
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
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
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
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
00454
00455 getTab(getCurrentPanelIndex())->mButton->setFocus(TRUE);
00456 }
00457 }
00458 gFocusMgr.setMouseCapture(NULL);
00459 }
00460 return handled;
00461 }
00462
00463
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
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
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
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
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
00671 return;
00672 }
00673 const LLFontGL* font = LLResMgr::getInstance()->getRes( mIsVertical ? LLFONT_SANSSERIF : LLFONT_SANSSERIF_SMALL );
00674
00675
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
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);
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
00720
00721 child->setVisible( FALSE );
00722
00723 mTotalTabWidth += button_width;
00724
00725
00726 LLRect btn_rect;
00727 LLString tab_img;
00728 LLString tab_selected_img;
00729 S32 tab_fudge = 1;
00730
00731 if (mIsVertical)
00732 {
00733 btn_rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2,
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,
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
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
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,
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
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
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
00905
00906 mTabList.erase( iter );
00907 delete tuple;
00908
00909 break;
00910 }
00911 }
00912
00913
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
00936
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
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
00965 }
00966
00967
00968 std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
00969 mTabList.clear();
00970
00971
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
01041 void LLTabContainer::setCurrentTabName(const LLString& name)
01042 {
01043
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
01125
01126
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
01147 tuple->mButton->setToggleState( is_selected );
01148
01149 tuple->mButton->setTabStop( is_selected );
01150
01151 if( is_selected && (mIsVertical || (getMaxScrollPos() > 0)))
01152 {
01153
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
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
01271 mTotalTabWidth += tuple->mButton->getRect().getWidth();
01272
01273
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
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
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
01375 void LLTabContainer::onNextBtn( void* userdata )
01376 {
01377
01378 LLTabContainer* self = (LLTabContainer*) userdata;
01379 if (!self->mScrolled)
01380 {
01381 self->scrollNext();
01382 }
01383 self->mScrolled = FALSE;
01384 }
01385
01386
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
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
01410 void LLTabContainer::onJumpFirstBtn( void* userdata )
01411 {
01412 LLTabContainer* self = (LLTabContainer*) userdata;
01413 self->mScrollPos = 0;
01414 }
01415
01416
01417 void LLTabContainer::onJumpLastBtn( void* userdata )
01418 {
01419 LLTabContainer* self = (LLTabContainer*) userdata;
01420 self->mScrollPos = self->mMaxScrollPos;
01421 }
01422
01423
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
01436 LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
01437 {
01438 LLString name("tab_container");
01439 node->getAttributeString("name", name);
01440
01441
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
01501
01502
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();
01528
01529 return tab_container;
01530 }
01531
01532
01533
01534 void LLTabContainer::initButtons()
01535 {
01536
01537 if (getRect().getHeight() == 0 || mPrevArrowBtn)
01538 {
01539 return;
01540 }
01541
01542 LLString out_id;
01543 LLString in_id;
01544
01545 if (mIsVertical)
01546 {
01547
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
01574 {
01575 S32 arrow_fudge = 1;
01576
01577
01578 if (getTabPosition() == BOTTOM)
01579 {
01580 mRightTabBtnOffset = RESIZE_HANDLE_WIDTH;
01581 }
01582
01583
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
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
01699 mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
01700 break;
01701 case LEFT_OF_CURRENT:
01702
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
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
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
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());
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