00001
00032
00033
00034 #include "linden_common.h"
00035
00036 #include "lltabcontainervertical.h"
00037
00038 #include "llfocusmgr.h"
00039 #include "llfontgl.h"
00040 #include "llgl.h"
00041
00042 #include "llbutton.h"
00043 #include "llrect.h"
00044 #include "llpanel.h"
00045 #include "llresmgr.h"
00046 #include "llkeyboard.h"
00047 #include "llui.h"
00048 #include "lltextbox.h"
00049 #include "llcontrol.h"
00050 #include "llcriticaldamp.h"
00051
00052 #include "llglheaders.h"
00053
00054 LLTabContainerVertical::LLTabContainerVertical(
00055 const LLString& name, const LLRect& rect,
00056 void(*close_callback)(void*), void* callback_userdata,
00057 U32 tab_width, BOOL bordered)
00058 :
00059 LLTabContainerCommon(name, rect, LEFT, close_callback, callback_userdata, bordered),
00060 mTabWidth(tab_width),
00061 mUpArrowBtn(NULL),
00062 mDownArrowBtn(NULL)
00063 {
00064 initButtons();
00065 }
00066
00067 LLTabContainerVertical::LLTabContainerVertical(
00068 const LLString& name, const LLString& rect_control,
00069 void(*close_callback)(void*), void* callback_userdata,
00070 U32 tab_width, BOOL bordered)
00071 :
00072 LLTabContainerCommon(name, rect_control, LEFT, close_callback, callback_userdata, bordered),
00073 mTabWidth(tab_width)
00074 {
00075 initButtons();
00076 }
00077
00078
00079 void LLTabContainerVertical::initButtons()
00080 {
00081
00082 if (mRect.getHeight() == 0 || mUpArrowBtn)
00083 {
00084 return;
00085 }
00086
00087 LLString out_id;
00088 LLString in_id;
00089
00090
00091
00092
00093 S32 btn_top = mRect.getHeight();
00094 S32 btn_top_lower = mRect.mBottom+TABCNTRV_ARROW_BTN_SIZE;
00095
00096 LLRect up_arrow_btn_rect;
00097 up_arrow_btn_rect.setLeftTopAndSize( mTabWidth/2 , btn_top, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );
00098
00099 LLRect down_arrow_btn_rect;
00100 down_arrow_btn_rect.setLeftTopAndSize( mTabWidth/2 , btn_top_lower, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );
00101
00102 out_id = "UIImgBtnScrollUpOutUUID";
00103 in_id = "UIImgBtnScrollUpInUUID";
00104 mUpArrowBtn = new LLButton(
00105 "Up Arrow", up_arrow_btn_rect,
00106 out_id, in_id, "",
00107 &onPrevBtn, this, NULL );
00108 mUpArrowBtn->setHeldDownCallback(onPrevBtnHeld);
00109 mUpArrowBtn->setSaveToXML(false);
00110 mUpArrowBtn->setFollowsTop();
00111 mUpArrowBtn->setFollowsLeft();
00112 mUpArrowBtn->setTabStop(FALSE);
00113 addChild(mUpArrowBtn);
00114
00115 out_id = "UIImgBtnScrollDownOutUUID";
00116 in_id = "UIImgBtnScrollDownInUUID";
00117 mDownArrowBtn = new LLButton(
00118 "Down Arrow", down_arrow_btn_rect,
00119 out_id, in_id, "",
00120 &onNextBtn, this, NULL );
00121 mDownArrowBtn->setHeldDownCallback(onNextBtnHeld);
00122 mDownArrowBtn->setSaveToXML(false);
00123 mDownArrowBtn->setFollowsBottom();
00124 mDownArrowBtn->setFollowsLeft();
00125 mDownArrowBtn->setTabStop(FALSE);
00126 addChild(mDownArrowBtn);
00127
00128
00129 mDefaultTabGroup = 1;
00130 }
00131
00132 LLTabContainerVertical::~LLTabContainerVertical()
00133 { }
00134
00135 void LLTabContainerVertical::addTabPanel(LLPanel* child, const LLString& label,
00136 BOOL select,
00137 void (*on_tab_clicked)(void*, bool), void* userdata,
00138 S32 indent,
00139 BOOL placeholder, eInsertionPoint insertion_point)
00140 {
00141 if (child->getParent() == this)
00142 {
00143
00144 return;
00145 }
00146
00147 const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF );
00148
00149
00150 child->setLabel(label);
00151
00152 LLString trimmed_label = label;
00153 LLString::trim(trimmed_label);
00154
00155
00156 S32 tab_panel_top;
00157 S32 tab_panel_bottom;
00158 tab_panel_top = mRect.getHeight()
00159 - mTopBorderHeight
00160 - (BTN_HEIGHT - TABCNTRV_BUTTON_PANEL_OVERLAP);
00161 tab_panel_bottom = LLPANEL_BORDER_WIDTH;
00162
00163 LLRect tab_panel_rect(
00164 mTabWidth + (LLPANEL_BORDER_WIDTH * 2) + TABCNTRV_PAD,
00165 mRect.getHeight() - LLPANEL_BORDER_WIDTH,
00166 mRect.getWidth() - LLPANEL_BORDER_WIDTH,
00167 LLPANEL_BORDER_WIDTH);
00168
00169 child->setFollowsAll();
00170 child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
00171 child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
00172 child->setBackgroundVisible( FALSE );
00173
00174 child->setVisible( FALSE );
00175
00176
00177 LLRect btn_rect;
00178 btn_rect.setLeftTopAndSize(
00179 TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2,
00180 (mRect.getHeight() - mTopBorderHeight - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * mTabList.size()),
00181 mTabWidth,
00182 BTN_HEIGHT);
00183
00184 if (!placeholder)
00185 {
00186 LLButton *btn = new LLButton("vert tab button",
00187 btn_rect,
00188 "tab_left.tga",
00189 "tab_left_selected.tga",
00190 "",
00191 &LLTabContainerVertical::onTabBtn, NULL,
00192 font,
00193 trimmed_label, trimmed_label);
00194 btn->setSaveToXML(false);
00195 btn->setFixedBorder(16, 16);
00196 btn->setScaleImage(TRUE);
00197 btn->setHAlign(LLFontGL::LEFT);
00198 btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
00199 btn->setTabStop(FALSE);
00200 if (indent)
00201 {
00202 btn->setLeftHPad(indent);
00203 }
00204
00205 LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata );
00206 insertTuple( tuple, insertion_point );
00207
00208 btn->setCallbackUserData( tuple );
00209 addChild( btn, 0 );
00210 addChild(child, 1);
00211
00212 if( select )
00213 {
00214 selectTab( mTabList.size()-1 );
00215 }
00216 }
00217 else
00218 {
00219 btn_rect.translate(0, -LLBUTTON_V_PAD-2);
00220 LLString box_label = trimmed_label;
00221 LLTextBox* text = new LLTextBox(box_label, btn_rect, box_label, font);
00222 text->setSaveToXML(false);
00223 addChild( text, 0 );
00224
00225 LLButton* btn = new LLButton("", LLRect(0,0,0,0));
00226 btn->setSaveToXML(false);
00227 addChild(btn, 0);
00228 addChild(child, 1);
00229
00230 LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, text );
00231 insertTuple( tuple, insertion_point );
00232 }
00233
00234 updateMaxScrollPos();
00235 }
00236
00237 void LLTabContainerVertical::removeTabPanel(LLPanel* child)
00238 {
00239 LLTabContainerCommon::removeTabPanel(child);
00240
00241
00242 S32 tab_count = 0;
00243 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00244 {
00245 LLTabTuple* tuple = *iter;
00246 LLRect rect;
00247 rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2,
00248 (mRect.getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * (tab_count)),
00249 mTabWidth,
00250 BTN_HEIGHT);
00251 if (tuple->mPlaceholderText)
00252 {
00253 tuple->mPlaceholderText->setRect(rect);
00254 }
00255 else
00256 {
00257 tuple->mButton->setRect(rect);
00258 }
00259 tab_count++;
00260 }
00261 }
00262
00263 void LLTabContainerVertical::updateMaxScrollPos()
00264 {
00265 S32 tab_total_height = (BTN_HEIGHT + TABCNTRV_PAD) * mTabList.size();
00266 S32 available_height = mRect.getHeight() - mTopBorderHeight;
00267 if( tab_total_height > available_height )
00268 {
00269 S32 available_height_with_arrows = mRect.getHeight() - 2*(TABCNTRV_ARROW_BTN_SIZE + 3*TABCNTRV_PAD);
00270 S32 additional_needed = tab_total_height - available_height_with_arrows;
00271 mMaxScrollPos = S32( ceil(additional_needed / float(BTN_HEIGHT) ) );
00272 }
00273 else
00274 {
00275 mMaxScrollPos = 0;
00276 mScrollPos = 0;
00277 }
00278 if (mScrollPos > mMaxScrollPos)
00279 {
00280 mScrollPos = mMaxScrollPos;
00281 }
00282 }
00283
00284 void LLTabContainerVertical::commitHoveredButton(S32 x, S32 y)
00285 {
00286 if (hasMouseCapture())
00287 {
00288 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00289 {
00290 LLTabTuple* tuple = *iter;
00291 tuple->mButton->setVisible( TRUE );
00292 S32 local_x = x - tuple->mButton->getRect().mLeft;
00293 S32 local_y = y - tuple->mButton->getRect().mBottom;
00294 if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
00295 {
00296 tuple->mButton->onCommit();
00297 }
00298 }
00299 }
00300 }
00301
00302 BOOL LLTabContainerVertical::selectTab(S32 which)
00303 {
00304 if (which >= (S32)mTabList.size()) return FALSE;
00305 if (which < 0) return FALSE;
00306
00307
00308
00309
00310
00311
00312 LLTabTuple* selected_tuple = mTabList[which];
00313 if (!selected_tuple)
00314 {
00315 return FALSE;
00316 }
00317
00318 BOOL is_visible = FALSE;
00319 if (which != mCurrentTabIdx)
00320 {
00321 mCurrentTabIdx = which;
00322
00323 S32 i = 0;
00324 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00325 {
00326 LLTabTuple* tuple = *iter;
00327 BOOL is_selected = ( tuple == selected_tuple );
00328 tuple->mTabPanel->setVisible( is_selected );
00329
00330 tuple->mButton->setToggleState( is_selected );
00331
00332 tuple->mButton->setTabStop( is_selected );
00333
00334 if( is_selected )
00335 {
00336
00337 S32 num_visible = mTabList.size() - mMaxScrollPos;
00338 if( i >= mScrollPos && i <= mScrollPos + num_visible)
00339 {
00340 mCurrentTabIdx = which;
00341 is_visible = TRUE;
00342 }
00343 else
00344 {
00345 is_visible = FALSE;
00346 }
00347 }
00348 i++;
00349 }
00350 if( selected_tuple->mOnChangeCallback )
00351 {
00352 selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false );
00353 }
00354 }
00355 if(mCurrentTabIdx >= 0)
00356 {
00357 LLTabTuple* tuple = mTabList[mCurrentTabIdx];
00358 tuple->mTabPanel->setVisible( TRUE );
00359 tuple->mButton->setToggleState( TRUE );
00360 }
00361 return is_visible;
00362 }
00363
00364
00365
00366 void LLTabContainerVertical::draw()
00367 {
00368 S32 target_pixel_scroll = mScrollPos * (BTN_HEIGHT + TABCNTRV_PAD);
00369
00370 mScrollPosPixels = (S32)lerp((F32)mScrollPosPixels, (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f));
00371 if( getVisible() )
00372 {
00373 BOOL has_scroll_arrows = (mMaxScrollPos > 0) || (mScrollPosPixels > 0);
00374 mUpArrowBtn->setVisible( has_scroll_arrows );
00375 mDownArrowBtn->setVisible( has_scroll_arrows );
00376
00377
00378 S32 top = mRect.getHeight() - mTopBorderHeight - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? TABCNTRV_ARROW_BTN_SIZE : 0);
00379 top += mScrollPosPixels;
00380
00381
00382 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00383 {
00384 LLTabTuple* tuple = *iter;
00385 tuple->mButton->setVisible( FALSE );
00386 }
00387
00388 LLPanel::draw();
00389
00390
00391 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00392 {
00393 LLTabTuple* tuple = *iter;
00394 tuple->mButton->setVisible( TRUE );
00395 }
00396
00397
00398 {
00399 LLRect clip_rect = getLocalRect();
00400 if (has_scroll_arrows)
00401 {
00402
00403 clip_rect.mBottom = mDownArrowBtn->getRect().mTop + 3*TABCNTRV_PAD;
00404 clip_rect.mTop = mUpArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD;
00405 }
00406 LLLocalClipRect clip(clip_rect);
00407
00408
00409 S32 idx = 0;
00410 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
00411 {
00412 LLTabTuple* tuple = *iter;
00413 tuple->mButton->translate( 0 , top - tuple->mButton->getRect().mTop);
00414 top -= BTN_HEIGHT + TABCNTRV_PAD;
00415
00416 LLUI::pushMatrix();
00417 {
00418 LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f);
00419 tuple->mButton->draw();
00420 }
00421 LLUI::popMatrix();
00422
00423 idx++;
00424 }
00425
00426 if( has_scroll_arrows )
00427 {
00428
00429 glPushMatrix();
00430 glTranslatef((F32)mUpArrowBtn->getRect().mLeft, (F32)mUpArrowBtn->getRect().mBottom, 0.f);
00431 mUpArrowBtn->draw();
00432 glPopMatrix();
00433
00434 glPushMatrix();
00435 glTranslatef((F32)mDownArrowBtn->getRect().mLeft, (F32)mDownArrowBtn->getRect().mBottom, 0.f);
00436 mDownArrowBtn->draw();
00437 glPopMatrix();
00438 }
00439 }
00440 }
00441 }
00442
00443 BOOL LLTabContainerVertical::handleMouseDown( S32 x, S32 y, MASK mask )
00444 {
00445 BOOL handled = FALSE;
00446 BOOL has_scroll_arrows = (mMaxScrollPos > 0);
00447
00448 if (has_scroll_arrows)
00449 {
00450 if (mUpArrowBtn->getRect().pointInRect(x, y))
00451 {
00452 S32 local_x = x - mUpArrowBtn->getRect().mLeft;
00453 S32 local_y = y - mUpArrowBtn->getRect().mBottom;
00454 handled = mUpArrowBtn->handleMouseDown(local_x, local_y, mask);
00455 }
00456 else if (mDownArrowBtn->getRect().pointInRect(x, y))
00457 {
00458 S32 local_x = x - mDownArrowBtn->getRect().mLeft;
00459 S32 local_y = y - mDownArrowBtn->getRect().mBottom;
00460 handled = mDownArrowBtn->handleMouseDown(local_x, local_y, mask);
00461 }
00462 }
00463 if (!handled)
00464 {
00465 handled = LLPanel::handleMouseDown( x, y, mask );
00466 }
00467
00468 if (mTabList.size() > 0)
00469 {
00470 LLTabTuple* firsttuple = mTabList[0];
00471 LLRect tab_rect(firsttuple->mButton->getRect().mLeft,
00472 has_scroll_arrows ? mUpArrowBtn->getRect().mBottom - TABCNTRV_PAD : mUpArrowBtn->getRect().mTop,
00473 firsttuple->mButton->getRect().mRight,
00474 has_scroll_arrows ? mDownArrowBtn->getRect().mTop + TABCNTRV_PAD : mDownArrowBtn->getRect().mBottom );
00475 if( tab_rect.pointInRect( x, y ) )
00476 {
00477 LLButton* tab_button = mTabList[getCurrentPanelIndex()]->mButton;
00478 gFocusMgr.setMouseCapture(this);
00479 gFocusMgr.setKeyboardFocus(tab_button, NULL);
00480 }
00481 }
00482 return handled;
00483 }
00484
00485 BOOL LLTabContainerVertical::handleHover( S32 x, S32 y, MASK mask )
00486 {
00487 BOOL handled = FALSE;
00488 BOOL has_scroll_arrows = (mMaxScrollPos > 0);
00489
00490 if (has_scroll_arrows)
00491 {
00492 if (mUpArrowBtn->getRect().pointInRect(x, y))
00493 {
00494 S32 local_x = x - mUpArrowBtn->getRect().mLeft;
00495 S32 local_y = y - mUpArrowBtn->getRect().mBottom;
00496 handled = mUpArrowBtn->handleHover(local_x, local_y, mask);
00497 }
00498 else if (mDownArrowBtn->getRect().pointInRect(x, y))
00499 {
00500 S32 local_x = x - mDownArrowBtn->getRect().mLeft;
00501 S32 local_y = y - mDownArrowBtn->getRect().mBottom;
00502 handled = mDownArrowBtn->handleHover(local_x, local_y, mask);
00503 }
00504 }
00505 if (!handled)
00506 {
00507 handled = LLPanel::handleHover(x, y, mask);
00508 }
00509
00510 commitHoveredButton(x, y);
00511 return handled;
00512 }
00513
00514 BOOL LLTabContainerVertical::handleMouseUp( S32 x, S32 y, MASK mask )
00515 {
00516 BOOL handled = FALSE;
00517 BOOL has_scroll_arrows = (mMaxScrollPos > 0);
00518
00519 if (has_scroll_arrows)
00520 {
00521 if (mUpArrowBtn->getRect().pointInRect(x, y))
00522 {
00523 S32 local_x = x - mUpArrowBtn->getRect().mLeft;
00524 S32 local_y = y - mUpArrowBtn->getRect().mBottom;
00525 handled = mUpArrowBtn->handleMouseUp(local_x, local_y, mask);
00526 }
00527 else if (mDownArrowBtn->getRect().pointInRect(x, y))
00528 {
00529 S32 local_x = x - mDownArrowBtn->getRect().mLeft;
00530 S32 local_y = y - mDownArrowBtn->getRect().mBottom;
00531 handled = mDownArrowBtn->handleMouseUp(local_x, local_y, mask);
00532 }
00533 }
00534 if (!handled)
00535 {
00536 handled = LLPanel::handleMouseUp( x, y, mask );
00537 }
00538
00539 commitHoveredButton(x, y);
00540 LLPanel* cur_panel = getCurrentPanel();
00541 if (hasMouseCapture())
00542 {
00543 if (cur_panel)
00544 {
00545 if (!cur_panel->focusFirstItem(FALSE))
00546 {
00547 mTabList[getCurrentPanelIndex()]->mButton->setFocus(TRUE);
00548 }
00549 }
00550 gFocusMgr.setMouseCapture(NULL);
00551 }
00552
00553 return handled;
00554 }
00555
00556 BOOL LLTabContainerVertical::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
00557 {
00558 BOOL handled = FALSE;
00559 if (getEnabled())
00560 {
00561 if (key == KEY_LEFT && mask == MASK_ALT)
00562 {
00563 selectPrevTab();
00564 handled = TRUE;
00565 }
00566 else if (key == KEY_RIGHT && mask == MASK_ALT)
00567 {
00568 selectNextTab();
00569 handled = TRUE;
00570 }
00571
00572
00573 if (!handled && !gFocusMgr.childHasKeyboardFocus(getCurrentPanel()))
00574 {
00575 switch(key)
00576 {
00577 case KEY_UP:
00578 selectPrevTab();
00579 handled = TRUE;
00580 break;
00581 case KEY_DOWN:
00582 selectNextTab();
00583 handled = TRUE;
00584 break;
00585 case KEY_LEFT:
00586 handled = TRUE;
00587 break;
00588 case KEY_RIGHT:
00589 if (getTabPosition() == LEFT && getCurrentPanel())
00590 {
00591 getCurrentPanel()->setFocus(TRUE);
00592 }
00593 handled = TRUE;
00594 break;
00595 default:
00596 break;
00597 }
00598 }
00599 }
00600 return handled;
00601 }
00602
00603
00604 LLXMLNodePtr LLTabContainerVertical::getXML(bool save_children) const
00605 {
00606 LLXMLNodePtr node = LLTabContainerCommon::getXML();
00607
00608
00609 node->createChild("tab_position", TRUE)->setStringValue("left");
00610
00611 return node;
00612 }