PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llui/lltabcontainer.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2048 lines | 1704 code | 220 blank | 124 comment | 321 complexity | b571075e307edeafc533c658902f4ba4 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lltabcontainer.cpp
  3. * @brief LLTabContainer class
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "lltabcontainer.h"
  28. #include "llfocusmgr.h"
  29. #include "lllocalcliprect.h"
  30. #include "llrect.h"
  31. #include "llresizehandle.h"
  32. #include "lltextbox.h"
  33. #include "llcriticaldamp.h"
  34. #include "lluictrlfactory.h"
  35. #include "llrender.h"
  36. #include "llfloater.h"
  37. #include "lltrans.h"
  38. //----------------------------------------------------------------------------
  39. // Implementation Notes:
  40. // - Each tab points to a LLPanel (see LLTabTuple below)
  41. // - When a tab is selected, the validation callback
  42. // (LLUICtrl::mValidateSignal) is called
  43. // - If the validation callback returns true (or none is provided),
  44. // the tab is changed and the commit callback
  45. // (LLUICtrl::mCommitSignal) is called
  46. // - Callbacks pass the LLTabContainer as the control,
  47. // and the NAME of the selected PANEL as the LLSD data
  48. //----------------------------------------------------------------------------
  49. const F32 SCROLL_STEP_TIME = 0.4f;
  50. const F32 SCROLL_DELAY_TIME = 0.5f;
  51. void LLTabContainer::TabPositions::declareValues()
  52. {
  53. declare("top", LLTabContainer::TOP);
  54. declare("bottom", LLTabContainer::BOTTOM);
  55. declare("left", LLTabContainer::LEFT);
  56. }
  57. //----------------------------------------------------------------------------
  58. // Structure used to map tab buttons to and from tab panels
  59. class LLTabTuple
  60. {
  61. public:
  62. LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, LLTextBox* placeholder = NULL)
  63. :
  64. mTabContainer(c),
  65. mTabPanel(p),
  66. mButton(b),
  67. mOldState(FALSE),
  68. mPlaceholderText(placeholder),
  69. mPadding(0)
  70. {}
  71. LLTabContainer* mTabContainer;
  72. LLPanel* mTabPanel;
  73. LLButton* mButton;
  74. BOOL mOldState;
  75. LLTextBox* mPlaceholderText;
  76. S32 mPadding;
  77. };
  78. //----------------------------------------------------------------------------
  79. //============================================================================
  80. /*
  81. * @file lltabcontainer.cpp
  82. * @brief class implements LLButton with LLIconCtrl on it
  83. */
  84. class LLCustomButtonIconCtrl : public LLButton
  85. {
  86. public:
  87. struct Params
  88. : public LLInitParam::Block<Params, LLButton::Params>
  89. {
  90. // LEFT, RIGHT, TOP, BOTTOM paddings of LLIconCtrl in this class has same value
  91. Optional<S32> icon_ctrl_pad;
  92. Params()
  93. : icon_ctrl_pad("icon_ctrl_pad", 1)
  94. {}
  95. };
  96. protected:
  97. friend class LLUICtrlFactory;
  98. LLCustomButtonIconCtrl(const Params& p)
  99. : LLButton(p),
  100. mIcon(NULL),
  101. mIconAlignment(LLFontGL::HCENTER),
  102. mIconCtrlPad(p.icon_ctrl_pad)
  103. {}
  104. public:
  105. void updateLayout()
  106. {
  107. LLRect button_rect = getRect();
  108. LLRect icon_rect = mIcon->getRect();
  109. S32 icon_size = button_rect.getHeight() - 2*mIconCtrlPad;
  110. switch(mIconAlignment)
  111. {
  112. case LLFontGL::LEFT:
  113. icon_rect.setLeftTopAndSize(button_rect.mLeft + mIconCtrlPad, button_rect.mTop - mIconCtrlPad,
  114. icon_size, icon_size);
  115. setLeftHPad(icon_size + mIconCtrlPad * 2);
  116. break;
  117. case LLFontGL::HCENTER:
  118. icon_rect.setLeftTopAndSize(button_rect.mRight - (button_rect.getWidth() + mIconCtrlPad - icon_size)/2, button_rect.mTop - mIconCtrlPad,
  119. icon_size, icon_size);
  120. setRightHPad(icon_size + mIconCtrlPad * 2);
  121. break;
  122. case LLFontGL::RIGHT:
  123. icon_rect.setLeftTopAndSize(button_rect.mRight - mIconCtrlPad - icon_size, button_rect.mTop - mIconCtrlPad,
  124. icon_size, icon_size);
  125. setRightHPad(icon_size + mIconCtrlPad * 2);
  126. break;
  127. default:
  128. break;
  129. }
  130. mIcon->setRect(icon_rect);
  131. }
  132. void setIcon(LLIconCtrl* icon, LLFontGL::HAlign alignment = LLFontGL::LEFT)
  133. {
  134. if(icon)
  135. {
  136. if(mIcon)
  137. {
  138. removeChild(mIcon);
  139. mIcon->die();
  140. }
  141. mIcon = icon;
  142. mIconAlignment = alignment;
  143. addChild(mIcon);
  144. updateLayout();
  145. }
  146. }
  147. LLIconCtrl* getIconCtrl() const
  148. {
  149. return mIcon;
  150. }
  151. private:
  152. LLIconCtrl* mIcon;
  153. LLFontGL::HAlign mIconAlignment;
  154. S32 mIconCtrlPad;
  155. };
  156. //============================================================================
  157. struct LLPlaceHolderPanel : public LLPanel
  158. {
  159. // create dummy param block to register with "placeholder" nane
  160. struct Params : public LLPanel::Params{};
  161. LLPlaceHolderPanel(const Params& p) : LLPanel(p)
  162. {}
  163. };
  164. static LLDefaultChildRegistry::Register<LLPlaceHolderPanel> r1("placeholder");
  165. static LLDefaultChildRegistry::Register<LLTabContainer> r2("tab_container");
  166. LLTabContainer::TabParams::TabParams()
  167. : tab_top_image_unselected("tab_top_image_unselected"),
  168. tab_top_image_selected("tab_top_image_selected"),
  169. tab_top_image_flash("tab_top_image_flash"),
  170. tab_bottom_image_unselected("tab_bottom_image_unselected"),
  171. tab_bottom_image_selected("tab_bottom_image_selected"),
  172. tab_bottom_image_flash("tab_bottom_image_flash"),
  173. tab_left_image_unselected("tab_left_image_unselected"),
  174. tab_left_image_selected("tab_left_image_selected"),
  175. tab_left_image_flash("tab_left_image_flash")
  176. {}
  177. LLTabContainer::Params::Params()
  178. : tab_width("tab_width"),
  179. tab_min_width("tab_min_width"),
  180. tab_max_width("tab_max_width"),
  181. tab_height("tab_height"),
  182. label_pad_bottom("label_pad_bottom"),
  183. label_pad_left("label_pad_left"),
  184. tab_position("tab_position"),
  185. hide_tabs("hide_tabs", false),
  186. tab_padding_right("tab_padding_right"),
  187. first_tab("first_tab"),
  188. middle_tab("middle_tab"),
  189. last_tab("last_tab"),
  190. use_custom_icon_ctrl("use_custom_icon_ctrl", false),
  191. open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false),
  192. tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0),
  193. use_ellipses("use_ellipses"),
  194. font_halign("halign")
  195. {}
  196. LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
  197. : LLPanel(p),
  198. mCurrentTabIdx(-1),
  199. mTabsHidden(p.hide_tabs),
  200. mScrolled(FALSE),
  201. mScrollPos(0),
  202. mScrollPosPixels(0),
  203. mMaxScrollPos(0),
  204. mTitleBox(NULL),
  205. mTopBorderHeight(LLPANEL_BORDER_WIDTH),
  206. mLockedTabCount(0),
  207. mMinTabWidth(0),
  208. mMaxTabWidth(p.tab_max_width),
  209. mTabHeight(p.tab_height),
  210. mLabelPadBottom(p.label_pad_bottom),
  211. mLabelPadLeft(p.label_pad_left),
  212. mPrevArrowBtn(NULL),
  213. mNextArrowBtn(NULL),
  214. mIsVertical( p.tab_position == LEFT ),
  215. // Horizontal Specific
  216. mJumpPrevArrowBtn(NULL),
  217. mJumpNextArrowBtn(NULL),
  218. mRightTabBtnOffset(p.tab_padding_right),
  219. mTotalTabWidth(0),
  220. mTabPosition(p.tab_position),
  221. mFontHalign(p.font_halign),
  222. mFont(p.font),
  223. mFirstTabParams(p.first_tab),
  224. mMiddleTabParams(p.middle_tab),
  225. mLastTabParams(p.last_tab),
  226. mCustomIconCtrlUsed(p.use_custom_icon_ctrl),
  227. mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop),
  228. mTabIconCtrlPad(p.tab_icon_ctrl_pad),
  229. mUseTabEllipses(p.use_ellipses)
  230. {
  231. static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
  232. mDragAndDropDelayTimer.stop();
  233. if (p.tab_width.isProvided())
  234. {
  235. mMinTabWidth = p.tab_width;
  236. }
  237. else if (!mIsVertical)
  238. {
  239. mMinTabWidth = p.tab_min_width;
  240. }
  241. else
  242. {
  243. // *HACK: support default min width for legacy vertical
  244. // tab containers
  245. mMinTabWidth = tabcntr_vert_tab_min_width;
  246. }
  247. initButtons( );
  248. }
  249. LLTabContainer::~LLTabContainer()
  250. {
  251. std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
  252. }
  253. //virtual
  254. void LLTabContainer::setValue(const LLSD& value)
  255. {
  256. selectTab((S32) value.asInteger());
  257. }
  258. //virtual
  259. void LLTabContainer::reshape(S32 width, S32 height, BOOL called_from_parent)
  260. {
  261. LLPanel::reshape( width, height, called_from_parent );
  262. updateMaxScrollPos();
  263. }
  264. //virtual
  265. LLView* LLTabContainer::getChildView(const std::string& name, BOOL recurse) const
  266. {
  267. tuple_list_t::const_iterator itor;
  268. for (itor = mTabList.begin(); itor != mTabList.end(); ++itor)
  269. {
  270. LLPanel *panel = (*itor)->mTabPanel;
  271. if (panel->getName() == name)
  272. {
  273. return panel;
  274. }
  275. }
  276. if (recurse)
  277. {
  278. for (itor = mTabList.begin(); itor != mTabList.end(); ++itor)
  279. {
  280. LLPanel *panel = (*itor)->mTabPanel;
  281. LLView *child = panel->getChildView(name, recurse);
  282. if (child)
  283. {
  284. return child;
  285. }
  286. }
  287. }
  288. return LLView::getChildView(name, recurse);
  289. }
  290. //virtual
  291. LLView* LLTabContainer::findChildView(const std::string& name, BOOL recurse) const
  292. {
  293. tuple_list_t::const_iterator itor;
  294. for (itor = mTabList.begin(); itor != mTabList.end(); ++itor)
  295. {
  296. LLPanel *panel = (*itor)->mTabPanel;
  297. if (panel->getName() == name)
  298. {
  299. return panel;
  300. }
  301. }
  302. if (recurse)
  303. {
  304. for (itor = mTabList.begin(); itor != mTabList.end(); ++itor)
  305. {
  306. LLPanel *panel = (*itor)->mTabPanel;
  307. LLView *child = panel->findChildView(name, recurse);
  308. if (child)
  309. {
  310. return child;
  311. }
  312. }
  313. }
  314. return LLView::findChildView(name, recurse);
  315. }
  316. bool LLTabContainer::addChild(LLView* view, S32 tab_group)
  317. {
  318. LLPanel* panelp = dynamic_cast<LLPanel*>(view);
  319. if (panelp)
  320. {
  321. addTabPanel(TabPanelParams().panel(panelp).label(panelp->getLabel()).is_placeholder(dynamic_cast<LLPlaceHolderPanel*>(view) != NULL));
  322. return true;
  323. }
  324. else
  325. {
  326. return LLUICtrl::addChild(view, tab_group);
  327. }
  328. }
  329. BOOL LLTabContainer::postBuild()
  330. {
  331. selectFirstTab();
  332. return TRUE;
  333. }
  334. // virtual
  335. void LLTabContainer::draw()
  336. {
  337. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  338. static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
  339. static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0);
  340. static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
  341. static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0);
  342. S32 target_pixel_scroll = 0;
  343. S32 cur_scroll_pos = getScrollPos();
  344. if (cur_scroll_pos > 0)
  345. {
  346. S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1);
  347. if (!mIsVertical)
  348. {
  349. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  350. {
  351. if (cur_scroll_pos == 0)
  352. {
  353. break;
  354. }
  355. target_pixel_scroll += (*iter)->mButton->getRect().getWidth();
  356. cur_scroll_pos--;
  357. }
  358. // Show part of the tab to the left of what is fully visible
  359. target_pixel_scroll -= tabcntr_tab_partial_width;
  360. // clamp so that rightmost tab never leaves right side of screen
  361. target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll);
  362. }
  363. }
  364. setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f)));
  365. BOOL has_scroll_arrows = !getTabsHidden() && ((mMaxScrollPos > 0) || (mScrollPosPixels > 0));
  366. if (!mIsVertical)
  367. {
  368. mJumpPrevArrowBtn->setVisible( has_scroll_arrows );
  369. mJumpNextArrowBtn->setVisible( has_scroll_arrows );
  370. }
  371. mPrevArrowBtn->setVisible( has_scroll_arrows );
  372. mNextArrowBtn->setVisible( has_scroll_arrows );
  373. S32 left = 0, top = 0;
  374. if (mIsVertical)
  375. {
  376. top = getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? tabcntrv_arrow_btn_size : 0);
  377. top += getScrollPosPixels();
  378. }
  379. else
  380. {
  381. // Set the leftmost position of the tab buttons.
  382. left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (tabcntr_arrow_btn_size * 2) : tabcntr_tab_h_pad);
  383. left -= getScrollPosPixels();
  384. }
  385. // Hide all the buttons
  386. if (getTabsHidden())
  387. {
  388. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  389. {
  390. LLTabTuple* tuple = *iter;
  391. tuple->mButton->setVisible( FALSE );
  392. }
  393. }
  394. {
  395. LLRect clip_rect = getLocalRect();
  396. clip_rect.mLeft+=(LLPANEL_BORDER_WIDTH + 2);
  397. clip_rect.mRight-=(LLPANEL_BORDER_WIDTH + 2);
  398. LLLocalClipRect clip(clip_rect);
  399. LLPanel::draw();
  400. }
  401. // if tabs are hidden, don't draw them and leave them in the invisible state
  402. if (!getTabsHidden())
  403. {
  404. // Show all the buttons
  405. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  406. {
  407. LLTabTuple* tuple = *iter;
  408. tuple->mButton->setVisible( TRUE );
  409. }
  410. S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos();
  411. S32 idx = 0;
  412. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  413. {
  414. LLTabTuple* tuple = *iter;
  415. tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0,
  416. top ? top - tuple->mButton->getRect().mTop : 0 );
  417. if (top) top -= BTN_HEIGHT + tabcntrv_pad;
  418. if (left) left += tuple->mButton->getRect().getWidth();
  419. if (!mIsVertical)
  420. {
  421. if( idx < getScrollPos() )
  422. {
  423. if( tuple->mButton->getFlashing() )
  424. {
  425. mPrevArrowBtn->setFlashing( TRUE );
  426. }
  427. }
  428. else if( max_scroll_visible < idx )
  429. {
  430. if( tuple->mButton->getFlashing() )
  431. {
  432. mNextArrowBtn->setFlashing( TRUE );
  433. }
  434. }
  435. }
  436. idx++;
  437. }
  438. if( mIsVertical && has_scroll_arrows )
  439. {
  440. // Redraw the arrows so that they appears on top.
  441. gGL.pushUIMatrix();
  442. gGL.translateUI((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f);
  443. mPrevArrowBtn->draw();
  444. gGL.popUIMatrix();
  445. gGL.pushUIMatrix();
  446. gGL.translateUI((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f);
  447. mNextArrowBtn->draw();
  448. gGL.popUIMatrix();
  449. }
  450. }
  451. mPrevArrowBtn->setFlashing(FALSE);
  452. mNextArrowBtn->setFlashing(FALSE);
  453. }
  454. // virtual
  455. BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
  456. {
  457. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  458. BOOL handled = FALSE;
  459. BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden();
  460. if (has_scroll_arrows)
  461. {
  462. if (mJumpPrevArrowBtn&& mJumpPrevArrowBtn->getRect().pointInRect(x, y))
  463. {
  464. S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
  465. S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
  466. handled = mJumpPrevArrowBtn->handleMouseDown(local_x, local_y, mask);
  467. }
  468. else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
  469. {
  470. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  471. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  472. handled = mJumpNextArrowBtn->handleMouseDown(local_x, local_y, mask);
  473. }
  474. else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
  475. {
  476. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  477. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  478. handled = mPrevArrowBtn->handleMouseDown(local_x, local_y, mask);
  479. }
  480. else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
  481. {
  482. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  483. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  484. handled = mNextArrowBtn->handleMouseDown(local_x, local_y, mask);
  485. }
  486. }
  487. if (!handled)
  488. {
  489. handled = LLPanel::handleMouseDown( x, y, mask );
  490. }
  491. S32 tab_count = getTabCount();
  492. if (tab_count > 0 && !getTabsHidden())
  493. {
  494. LLTabTuple* firsttuple = getTab(0);
  495. LLRect tab_rect;
  496. if (mIsVertical)
  497. {
  498. tab_rect = LLRect(firsttuple->mButton->getRect().mLeft,
  499. has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop,
  500. firsttuple->mButton->getRect().mRight,
  501. has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom );
  502. }
  503. else
  504. {
  505. tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft,
  506. firsttuple->mButton->getRect().mTop,
  507. has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight,
  508. firsttuple->mButton->getRect().mBottom );
  509. }
  510. if( tab_rect.pointInRect( x, y ) )
  511. {
  512. S32 index = getCurrentPanelIndex();
  513. index = llclamp(index, 0, tab_count-1);
  514. LLButton* tab_button = getTab(index)->mButton;
  515. gFocusMgr.setMouseCapture(this);
  516. tab_button->setFocus(TRUE);
  517. }
  518. }
  519. return handled;
  520. }
  521. // virtual
  522. BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask )
  523. {
  524. BOOL handled = FALSE;
  525. BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden();
  526. if (has_scroll_arrows)
  527. {
  528. if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
  529. {
  530. S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
  531. S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
  532. handled = mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
  533. }
  534. else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
  535. {
  536. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  537. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  538. handled = mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
  539. }
  540. else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
  541. {
  542. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  543. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  544. handled = mPrevArrowBtn->handleHover(local_x, local_y, mask);
  545. }
  546. else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
  547. {
  548. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  549. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  550. handled = mNextArrowBtn->handleHover(local_x, local_y, mask);
  551. }
  552. }
  553. if (!handled)
  554. {
  555. handled = LLPanel::handleHover(x, y, mask);
  556. }
  557. commitHoveredButton(x, y);
  558. return handled;
  559. }
  560. // virtual
  561. BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
  562. {
  563. BOOL handled = FALSE;
  564. BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden();
  565. if (has_scroll_arrows)
  566. {
  567. if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
  568. {
  569. S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
  570. S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
  571. handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
  572. }
  573. else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
  574. {
  575. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  576. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  577. handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask);
  578. }
  579. else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
  580. {
  581. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  582. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  583. handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
  584. }
  585. else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
  586. {
  587. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  588. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  589. handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask);
  590. }
  591. }
  592. if (!handled)
  593. {
  594. handled = LLPanel::handleMouseUp( x, y, mask );
  595. }
  596. commitHoveredButton(x, y);
  597. LLPanel* cur_panel = getCurrentPanel();
  598. if (hasMouseCapture())
  599. {
  600. if (cur_panel)
  601. {
  602. if (!cur_panel->focusFirstItem(FALSE))
  603. {
  604. // if nothing in the panel gets focus, make sure the new tab does
  605. // otherwise the last tab might keep focus
  606. getTab(getCurrentPanelIndex())->mButton->setFocus(TRUE);
  607. }
  608. }
  609. gFocusMgr.setMouseCapture(NULL);
  610. }
  611. return handled;
  612. }
  613. // virtual
  614. BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask)
  615. {
  616. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  617. BOOL handled = LLPanel::handleToolTip( x, y, mask);
  618. if (!handled && getTabCount() > 0 && !getTabsHidden())
  619. {
  620. LLTabTuple* firsttuple = getTab(0);
  621. BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
  622. LLRect clip;
  623. if (mIsVertical)
  624. {
  625. clip = LLRect(firsttuple->mButton->getRect().mLeft,
  626. has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop,
  627. firsttuple->mButton->getRect().mRight,
  628. has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom );
  629. }
  630. else
  631. {
  632. clip = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft,
  633. firsttuple->mButton->getRect().mTop,
  634. has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight,
  635. firsttuple->mButton->getRect().mBottom );
  636. }
  637. if( clip.pointInRect( x, y ) )
  638. {
  639. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  640. {
  641. LLTabTuple* tuple = *iter;
  642. tuple->mButton->setVisible( TRUE );
  643. S32 local_x = x - tuple->mButton->getRect().mLeft;
  644. S32 local_y = y - tuple->mButton->getRect().mBottom;
  645. handled = tuple->mButton->handleToolTip( local_x, local_y, mask);
  646. if( handled )
  647. {
  648. break;
  649. }
  650. }
  651. }
  652. }
  653. return handled;
  654. }
  655. // virtual
  656. BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask)
  657. {
  658. BOOL handled = FALSE;
  659. if (key == KEY_LEFT && mask == MASK_ALT)
  660. {
  661. selectPrevTab();
  662. handled = TRUE;
  663. }
  664. else if (key == KEY_RIGHT && mask == MASK_ALT)
  665. {
  666. selectNextTab();
  667. handled = TRUE;
  668. }
  669. if (handled)
  670. {
  671. if (getCurrentPanel())
  672. {
  673. getCurrentPanel()->setFocus(TRUE);
  674. }
  675. }
  676. if (!gFocusMgr.childHasKeyboardFocus(getCurrentPanel()))
  677. {
  678. // if child has focus, but not the current panel, focus is on a button
  679. if (mIsVertical)
  680. {
  681. switch(key)
  682. {
  683. case KEY_UP:
  684. selectPrevTab();
  685. handled = TRUE;
  686. break;
  687. case KEY_DOWN:
  688. selectNextTab();
  689. handled = TRUE;
  690. break;
  691. case KEY_LEFT:
  692. handled = TRUE;
  693. break;
  694. case KEY_RIGHT:
  695. if (getTabPosition() == LEFT && getCurrentPanel())
  696. {
  697. getCurrentPanel()->setFocus(TRUE);
  698. }
  699. handled = TRUE;
  700. break;
  701. default:
  702. break;
  703. }
  704. }
  705. else
  706. {
  707. switch(key)
  708. {
  709. case KEY_UP:
  710. if (getTabPosition() == BOTTOM && getCurrentPanel())
  711. {
  712. getCurrentPanel()->setFocus(TRUE);
  713. }
  714. handled = TRUE;
  715. break;
  716. case KEY_DOWN:
  717. if (getTabPosition() == TOP && getCurrentPanel())
  718. {
  719. getCurrentPanel()->setFocus(TRUE);
  720. }
  721. handled = TRUE;
  722. break;
  723. case KEY_LEFT:
  724. selectPrevTab();
  725. handled = TRUE;
  726. break;
  727. case KEY_RIGHT:
  728. selectNextTab();
  729. handled = TRUE;
  730. break;
  731. default:
  732. break;
  733. }
  734. }
  735. }
  736. return handled;
  737. }
  738. // virtual
  739. BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType type, void* cargo_data, EAcceptance *accept, std::string &tooltip)
  740. {
  741. BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
  742. if(mOpenTabsOnDragAndDrop && !getTabsHidden())
  743. {
  744. // In that case, we'll open the hovered tab while dragging and dropping items.
  745. // This allows for drilling through tabs.
  746. if (mDragAndDropDelayTimer.getStarted())
  747. {
  748. if (mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME)
  749. {
  750. if (has_scroll_arrows)
  751. {
  752. if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
  753. {
  754. S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
  755. S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
  756. mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
  757. }
  758. if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
  759. {
  760. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  761. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  762. mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
  763. }
  764. if (mPrevArrowBtn->getRect().pointInRect(x, y))
  765. {
  766. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  767. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  768. mPrevArrowBtn->handleHover(local_x, local_y, mask);
  769. }
  770. else if (mNextArrowBtn->getRect().pointInRect(x, y))
  771. {
  772. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  773. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  774. mNextArrowBtn->handleHover(local_x, local_y, mask);
  775. }
  776. }
  777. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  778. {
  779. LLTabTuple* tuple = *iter;
  780. tuple->mButton->setVisible( TRUE );
  781. S32 local_x = x - tuple->mButton->getRect().mLeft;
  782. S32 local_y = y - tuple->mButton->getRect().mBottom;
  783. if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
  784. {
  785. tuple->mButton->onCommit();
  786. }
  787. }
  788. // Stop the timer whether successful or not. Don't let it run forever.
  789. mDragAndDropDelayTimer.stop();
  790. }
  791. }
  792. else
  793. {
  794. // Start a timer so we don't open tabs as soon as we hover on them
  795. mDragAndDropDelayTimer.start();
  796. }
  797. }
  798. return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip);
  799. }
  800. void LLTabContainer::addTabPanel(LLPanel* panelp)
  801. {
  802. addTabPanel(TabPanelParams().panel(panelp));
  803. }
  804. // function to update images
  805. void LLTabContainer::update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos)
  806. {
  807. if (tuple && tuple->mButton)
  808. {
  809. if (pos == LLTabContainer::TOP)
  810. {
  811. tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_top_image_unselected));
  812. tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_top_image_selected));
  813. tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_top_image_flash));
  814. }
  815. else if (pos == LLTabContainer::BOTTOM)
  816. {
  817. tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_bottom_image_unselected));
  818. tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_bottom_image_selected));
  819. tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_bottom_image_flash));
  820. }
  821. else if (pos == LLTabContainer::LEFT)
  822. {
  823. tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_left_image_unselected));
  824. tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_left_image_selected));
  825. tuple->mButton->setImageFlash(static_cast<LLUIImage*>(params.tab_left_image_flash));
  826. }
  827. }
  828. }
  829. void LLTabContainer::addTabPanel(const TabPanelParams& panel)
  830. {
  831. LLPanel* child = panel.panel();
  832. llassert(child);
  833. if (!child) return;
  834. const std::string& label = panel.label.isProvided()
  835. ? panel.label()
  836. : panel.panel()->getLabel();
  837. BOOL select = panel.select_tab();
  838. S32 indent = panel.indent();
  839. BOOL placeholder = panel.is_placeholder;
  840. eInsertionPoint insertion_point = panel.insert_at();
  841. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  842. static LLUICachedControl<S32> tabcntr_button_panel_overlap ("UITabCntrButtonPanelOverlap", 0);
  843. static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
  844. if (child->getParent() == this)
  845. {
  846. // already a child of mine
  847. return;
  848. }
  849. // Store the original label for possible xml export.
  850. child->setLabel(label);
  851. std::string trimmed_label = label;
  852. LLStringUtil::trim(trimmed_label);
  853. S32 button_width = mMinTabWidth;
  854. if (!mIsVertical)
  855. {
  856. button_width = llclamp(mFont->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth);
  857. }
  858. // Tab panel
  859. S32 tab_panel_top;
  860. S32 tab_panel_bottom;
  861. if (!getTabsHidden())
  862. {
  863. if( getTabPosition() == LLTabContainer::TOP )
  864. {
  865. S32 tab_height = mIsVertical ? BTN_HEIGHT : mTabHeight;
  866. tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - tabcntr_button_panel_overlap);
  867. tab_panel_bottom = LLPANEL_BORDER_WIDTH;
  868. }
  869. else
  870. {
  871. tab_panel_top = getRect().getHeight() - getTopBorderHeight();
  872. tab_panel_bottom = (mTabHeight - tabcntr_button_panel_overlap); // Run to the edge, covering up the border
  873. }
  874. }
  875. else
  876. {
  877. //Scip tab button space if they are invisible(EXT - 576)
  878. tab_panel_top = getRect().getHeight();
  879. tab_panel_bottom = LLPANEL_BORDER_WIDTH;
  880. }
  881. LLRect tab_panel_rect;
  882. if (!getTabsHidden() && mIsVertical)
  883. {
  884. tab_panel_rect = LLRect(mMinTabWidth + mRightTabBtnOffset + (LLPANEL_BORDER_WIDTH * 2) + tabcntrv_pad,
  885. getRect().getHeight() - LLPANEL_BORDER_WIDTH,
  886. getRect().getWidth() - LLPANEL_BORDER_WIDTH,
  887. LLPANEL_BORDER_WIDTH);
  888. }
  889. else
  890. {
  891. tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH,
  892. tab_panel_top,
  893. getRect().getWidth()-LLPANEL_BORDER_WIDTH,
  894. tab_panel_bottom );
  895. }
  896. child->setFollowsAll();
  897. child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
  898. child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
  899. // add this child later
  900. child->setVisible( FALSE ); // Will be made visible when selected
  901. mTotalTabWidth += button_width;
  902. // Tab button
  903. LLRect btn_rect; // Note: btn_rect.mLeft is just a dummy. Will be updated in draw().
  904. LLUIImage* tab_img = NULL;
  905. LLUIImage* tab_selected_img = NULL;
  906. S32 tab_fudge = 1; // To make new tab art look better, nudge buttons up 1 pel
  907. if (mIsVertical)
  908. {
  909. btn_rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
  910. (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * getTabCount()),
  911. mMinTabWidth,
  912. BTN_HEIGHT);
  913. }
  914. else if( getTabPosition() == LLTabContainer::TOP )
  915. {
  916. btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, mTabHeight);
  917. tab_img = mMiddleTabParams.tab_top_image_unselected;
  918. tab_selected_img = mMiddleTabParams.tab_top_image_selected;
  919. }
  920. else
  921. {
  922. btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, mTabHeight);
  923. tab_img = mMiddleTabParams.tab_bottom_image_unselected;
  924. tab_selected_img = mMiddleTabParams.tab_bottom_image_selected;
  925. }
  926. LLTextBox* textbox = NULL;
  927. LLButton* btn = NULL;
  928. LLCustomButtonIconCtrl::Params custom_btn_params;
  929. {
  930. custom_btn_params.icon_ctrl_pad(mTabIconCtrlPad);
  931. }
  932. LLButton::Params normal_btn_params;
  933. if (placeholder)
  934. {
  935. btn_rect.translate(0, -6); // *TODO: make configurable
  936. LLTextBox::Params params;
  937. params.name(trimmed_label);
  938. params.rect(btn_rect);
  939. params.initial_value(trimmed_label);
  940. params.font(mFont);
  941. textbox = LLUICtrlFactory::create<LLTextBox> (params);
  942. LLButton::Params p;
  943. p.name("placeholder");
  944. btn = LLUICtrlFactory::create<LLButton>(p);
  945. }
  946. else
  947. {
  948. LLButton::Params& p = (mCustomIconCtrlUsed ? custom_btn_params : normal_btn_params);
  949. p.rect(btn_rect);
  950. p.font(mFont);
  951. p.font_halign = mFontHalign;
  952. p.label(trimmed_label);
  953. p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
  954. if (indent)
  955. {
  956. p.pad_left(indent);
  957. }
  958. p.pad_bottom( mLabelPadBottom );
  959. p.scale_image(true);
  960. p.tab_stop(false);
  961. p.label_shadow(false);
  962. p.follows.flags = FOLLOWS_LEFT;
  963. if (mIsVertical)
  964. {
  965. p.name(std::string("vert tab button"));
  966. p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
  967. p.image_selected(mMiddleTabParams.tab_left_image_selected);
  968. p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
  969. }
  970. else
  971. {
  972. p.name(std::string(child->getName()) + " tab");
  973. p.visible(false);
  974. p.image_unselected(tab_img);
  975. p.image_selected(tab_selected_img);
  976. p.follows.flags = p.follows.flags() | (getTabPosition() == TOP ? FOLLOWS_TOP : FOLLOWS_BOTTOM);
  977. // Try to squeeze in a bit more text
  978. p.pad_left( mLabelPadLeft );
  979. p.pad_right(2);
  980. }
  981. // *TODO : It seems wrong not to use p in both cases considering the way p is initialized
  982. if (mCustomIconCtrlUsed)
  983. {
  984. btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params);
  985. }
  986. else
  987. {
  988. btn = LLUICtrlFactory::create<LLButton>(p);
  989. }
  990. }
  991. LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox );
  992. insertTuple( tuple, insertion_point );
  993. // if new tab was added as a first or last tab, update button image
  994. // and update button image of any tab it may have affected
  995. if (tuple == mTabList.front())
  996. {
  997. update_images(tuple, mFirstTabParams, getTabPosition());
  998. if (mTabList.size() == 2)
  999. {
  1000. update_images(mTabList[1], mLastTabParams, getTabPosition());
  1001. }
  1002. else if (mTabList.size() > 2)
  1003. {
  1004. update_images(mTabList[1], mMiddleTabParams, getTabPosition());
  1005. }
  1006. }
  1007. else if (tuple == mTabList.back())
  1008. {
  1009. update_images(tuple, mLastTabParams, getTabPosition());
  1010. if (mTabList.size() > 2)
  1011. {
  1012. update_images(mTabList[mTabList.size()-2], mMiddleTabParams, getTabPosition());
  1013. }
  1014. }
  1015. //Don't add button and textbox if tab buttons are invisible(EXT - 576)
  1016. if (!getTabsHidden())
  1017. {
  1018. if (textbox)
  1019. {
  1020. addChild( textbox, 0 );
  1021. }
  1022. if (btn)
  1023. {
  1024. addChild( btn, 0 );
  1025. }
  1026. }
  1027. if (child)
  1028. {
  1029. LLUICtrl::addChild(child, 1);
  1030. }
  1031. sendChildToFront(mPrevArrowBtn);
  1032. sendChildToFront(mNextArrowBtn);
  1033. sendChildToFront(mJumpPrevArrowBtn);
  1034. sendChildToFront(mJumpNextArrowBtn);
  1035. if( select )
  1036. {
  1037. selectLastTab();
  1038. }
  1039. updateMaxScrollPos();
  1040. }
  1041. void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label)
  1042. {
  1043. addTabPanel(TabPanelParams().panel(child).label(label).is_placeholder(true));
  1044. }
  1045. void LLTabContainer::removeTabPanel(LLPanel* child)
  1046. {
  1047. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  1048. if (mIsVertical)
  1049. {
  1050. // Fix-up button sizes
  1051. S32 tab_count = 0;
  1052. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1053. {
  1054. LLTabTuple* tuple = *iter;
  1055. LLRect rect;
  1056. rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
  1057. (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * (tab_count)),
  1058. mMinTabWidth,
  1059. BTN_HEIGHT);
  1060. if (tuple->mPlaceholderText)
  1061. {
  1062. tuple->mPlaceholderText->setRect(rect);
  1063. }
  1064. else
  1065. {
  1066. tuple->mButton->setRect(rect);
  1067. }
  1068. tab_count++;
  1069. }
  1070. }
  1071. else
  1072. {
  1073. // Adjust the total tab width.
  1074. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1075. {
  1076. LLTabTuple* tuple = *iter;
  1077. if( tuple->mTabPanel == child )
  1078. {
  1079. mTotalTabWidth -= tuple->mButton->getRect().getWidth();
  1080. break;
  1081. }
  1082. }
  1083. }
  1084. BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this);
  1085. // If the tab being deleted is the selected one, select a different tab.
  1086. for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1087. {
  1088. LLTabTuple* tuple = *iter;
  1089. if( tuple->mTabPanel == child )
  1090. {
  1091. // update tab button images if removing the first or last tab
  1092. if ((tuple == mTabList.front()) && (mTabList.size() > 1))
  1093. {
  1094. update_images(mTabList[1], mFirstTabParams, getTabPosition());
  1095. }
  1096. else if ((tuple == mTabList.back()) && (mTabList.size() > 2))
  1097. {
  1098. update_images(mTabList[mTabList.size()-2], mLastTabParams, getTabPosition());
  1099. }
  1100. removeChild( tuple->mButton );
  1101. delete tuple->mButton;
  1102. removeChild( tuple->mTabPanel );
  1103. // delete tuple->mTabPanel;
  1104. mTabList.erase( iter );
  1105. delete tuple;
  1106. break;
  1107. }
  1108. }
  1109. // make sure we don't have more locked tabs than we have tabs
  1110. mLockedTabCount = llmin(getTabCount(), mLockedTabCount);
  1111. if (mCurrentTabIdx >= (S32)mTabList.size())
  1112. {
  1113. mCurrentTabIdx = mTabList.size()-1;
  1114. }
  1115. selectTab(mCurrentTabIdx);
  1116. if (has_focus)
  1117. {
  1118. LLPanel* panelp = getPanelByIndex(mCurrentTabIdx);
  1119. if (panelp)
  1120. {
  1121. panelp->setFocus(TRUE);
  1122. }
  1123. }
  1124. updateMaxScrollPos();
  1125. }
  1126. void LLTabContainer::lockTabs(S32 num_tabs)
  1127. {
  1128. // count current tabs or use supplied value and ensure no new tabs get
  1129. // inserted between them
  1130. mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount();
  1131. }
  1132. void LLTabContainer::unlockTabs()
  1133. {
  1134. mLockedTabCount = 0;
  1135. }
  1136. void LLTabContainer::enableTabButton(S32 which, BOOL enable)
  1137. {
  1138. if (which >= 0 && which < (S32)mTabList.size())
  1139. {
  1140. mTabList[which]->mButton->setEnabled(enable);
  1141. }
  1142. // Stop the DaD timer as it might run forever
  1143. // enableTabButton() is typically called on refresh and draw when anything changed
  1144. // in the tab container so it's a good time to reset that.
  1145. mDragAndDropDelayTimer.stop();
  1146. }
  1147. void LLTabContainer::deleteAllTabs()
  1148. {
  1149. // Remove all the tab buttons and delete them. Also, unlink all the child panels.
  1150. for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1151. {
  1152. LLTabTuple* tuple = *iter;
  1153. removeChild( tuple->mButton );
  1154. delete tuple->mButton;
  1155. removeChild( tuple->mTabPanel );
  1156. // delete tuple->mTabPanel;
  1157. }
  1158. // Actually delete the tuples themselves
  1159. std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
  1160. mTabList.clear();
  1161. // And there isn't a current tab any more
  1162. mCurrentTabIdx = -1;
  1163. }
  1164. LLPanel* LLTabContainer::getCurrentPanel()
  1165. {
  1166. if (mCurrentTabIdx >= 0 && mCurrentTabIdx < (S32) mTabList.size())
  1167. {
  1168. return mTabList[mCurrentTabIdx]->mTabPanel;
  1169. }
  1170. return NULL;
  1171. }
  1172. S32 LLTabContainer::getCurrentPanelIndex()
  1173. {
  1174. return mCurrentTabIdx;
  1175. }
  1176. S32 LLTabContainer::getTabCount()
  1177. {
  1178. return mTabList.size();
  1179. }
  1180. LLPanel* LLTabContainer::getPanelByIndex(S32 index)
  1181. {
  1182. if (index >= 0 && index < (S32)mTabList.size())
  1183. {
  1184. return mTabList[index]->mTabPanel;
  1185. }
  1186. return NULL;
  1187. }
  1188. S32 LLTabContainer::getIndexForPanel(LLPanel* panel)
  1189. {
  1190. for (S32 index = 0; index < (S32)mTabList.size(); index++)
  1191. {
  1192. if (mTabList[index]->mTabPanel == panel)
  1193. {
  1194. return index;
  1195. }
  1196. }
  1197. return -1;
  1198. }
  1199. S32 LLTabContainer::getPanelIndexByTitle(const std::string& title)
  1200. {
  1201. for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
  1202. {
  1203. if (title == mTabList[index]->mButton->getLabelSelected())
  1204. {
  1205. return index;
  1206. }
  1207. }
  1208. return -1;
  1209. }
  1210. LLPanel* LLTabContainer::getPanelByName(const std::string& name)
  1211. {
  1212. for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
  1213. {
  1214. LLPanel *panel = mTabList[index]->mTabPanel;
  1215. if (name == panel->getName())
  1216. {
  1217. return panel;
  1218. }
  1219. }
  1220. return NULL;
  1221. }
  1222. // Change the name of the button for the current tab.
  1223. void LLTabContainer::setCurrentTabName(const std::string& name)
  1224. {
  1225. // Might not have a tab selected
  1226. if (mCurrentTabIdx < 0) return;
  1227. mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name);
  1228. mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name);
  1229. }
  1230. void LLTabContainer::selectFirstTab()
  1231. {
  1232. selectTab( 0 );
  1233. }
  1234. void LLTabContainer::selectLastTab()
  1235. {
  1236. selectTab( mTabList.size()-1 );
  1237. }
  1238. void LLTabContainer::selectNextTab()
  1239. {
  1240. BOOL tab_has_focus = FALSE;
  1241. if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
  1242. {
  1243. tab_has_focus = TRUE;
  1244. }
  1245. S32 idx = mCurrentTabIdx+1;
  1246. if (idx >= (S32)mTabList.size())
  1247. idx = 0;
  1248. while (!selectTab(idx) && idx != mCurrentTabIdx)
  1249. {
  1250. idx = (idx + 1 ) % (S32)mTabList.size();
  1251. }
  1252. if (tab_has_focus)
  1253. {
  1254. mTabList[idx]->mButton->setFocus(TRUE);
  1255. }
  1256. }
  1257. void LLTabContainer::selectPrevTab()
  1258. {
  1259. BOOL tab_has_focus = FALSE;
  1260. if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
  1261. {
  1262. tab_has_focus = TRUE;
  1263. }
  1264. S32 idx = mCurrentTabIdx-1;
  1265. if (idx < 0)
  1266. idx = mTabList.size()-1;
  1267. while (!selectTab(idx) && idx != mCurrentTabIdx)
  1268. {
  1269. idx = idx - 1;
  1270. if (idx < 0)
  1271. idx = mTabList.size()-1;
  1272. }
  1273. if (tab_has_focus)
  1274. {
  1275. mTabList[idx]->mButton->setFocus(TRUE);
  1276. }
  1277. }
  1278. BOOL LLTabContainer::selectTabPanel(LLPanel* child)
  1279. {
  1280. S32 idx = 0;
  1281. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1282. {
  1283. LLTabTuple* tuple = *iter;
  1284. if( tuple->mTabPanel == child )
  1285. {
  1286. return selectTab( idx );
  1287. }
  1288. idx++;
  1289. }
  1290. return FALSE;
  1291. }
  1292. BOOL LLTabContainer::selectTab(S32 which)
  1293. {
  1294. if (which >= getTabCount() || which < 0)
  1295. return FALSE;
  1296. LLTabTuple* selected_tuple = getTab(which);
  1297. if (!selected_tuple)
  1298. {
  1299. return FALSE;
  1300. }
  1301. LLSD cbdata;
  1302. if (selected_tuple->mTabPanel)
  1303. cbdata = selected_tuple->mTabPanel->getName();
  1304. BOOL res = FALSE;
  1305. if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) )
  1306. {
  1307. res = setTab(which);
  1308. if (res && mCommitSignal)
  1309. {
  1310. (*mCommitSignal)(this, cbdata);
  1311. }
  1312. }
  1313. return res;
  1314. }
  1315. // private
  1316. BOOL LLTabContainer::setTab(S32 which)
  1317. {
  1318. static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
  1319. LLTabTuple* selected_tuple = getTab(which);
  1320. if (!selected_tuple)
  1321. {
  1322. return FALSE;
  1323. }
  1324. BOOL is_visible = FALSE;
  1325. if (selected_tuple->mButton->getEnabled())
  1326. {
  1327. setCurrentPanelIndex(which);
  1328. S32 i = 0;
  1329. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1330. {
  1331. LLTabTuple* tuple = *iter;
  1332. BOOL is_selected = ( tuple == selected_tuple );
  1333. tuple->mButton->setUseEllipses(mUseTabEllipses);
  1334. tuple->mButton->setHAlign(mFontHalign);
  1335. tuple->mTabPanel->setVisible( is_selected );
  1336. // tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here.
  1337. tuple->mButton->setToggleState( is_selected );
  1338. // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs
  1339. tuple->mButton->setTabStop( is_selected );
  1340. if (is_selected)
  1341. {
  1342. // Make sure selected tab is within scroll region
  1343. if (mIsVertical)
  1344. {
  1345. S32 num_visible = getTabCount() - getMaxScrollPos();
  1346. if( i >= getScrollPos() && i <= getScrollPos() + num_visible)
  1347. {
  1348. setCurrentPanelIndex(which);
  1349. is_visible = TRUE;
  1350. }
  1351. else
  1352. {
  1353. is_visible = FALSE;
  1354. }
  1355. }
  1356. else if (getMaxScrollPos() > 0)
  1357. {
  1358. if( i < getScrollPos() )
  1359. {
  1360. setScrollPos(i);
  1361. }
  1362. else
  1363. {
  1364. S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1);
  1365. S32 running_tab_width = tuple->mButton->getRect().getWidth();
  1366. S32 j = i - 1;
  1367. S32 min_scroll_pos = i;
  1368. if (running_tab_width < available_width_with_arrows)
  1369. {
  1370. while (j >= 0)
  1371. {
  1372. LLTabTuple* other_tuple = getTab(j);
  1373. running_tab_width += other_tuple->mButton->getRect().getWidth();
  1374. if (running_tab_width > available_width_with_arrows)
  1375. {
  1376. break;
  1377. }
  1378. j--;
  1379. }
  1380. min_scroll_pos = j + 1;
  1381. }
  1382. setScrollPos(llclamp(getScrollPos(), min_scroll_pos, i));
  1383. setScrollPos(llmin(getScrollPos(), getMaxScrollPos()));
  1384. }
  1385. is_visible = TRUE;
  1386. }
  1387. else
  1388. {
  1389. is_visible = TRUE;
  1390. }
  1391. }
  1392. i++;
  1393. }
  1394. }
  1395. if (mIsVertical && getCurrentPanelIndex() >= 0)
  1396. {
  1397. LLTabTuple* tuple = getTab(getCurrentPanelIndex());
  1398. tuple->mTabPanel->setVisible( TRUE );
  1399. tuple->mButton->setToggleState( TRUE );
  1400. }
  1401. return is_visible;
  1402. }
  1403. BOOL LLTabContainer::selectTabByName(const std::string& name)
  1404. {
  1405. LLPanel* panel = getPanelByName(name);
  1406. if (!panel)
  1407. {
  1408. llwarns << "LLTabContainer::selectTabByName("
  1409. << name << ") failed" << llendl;
  1410. return FALSE;
  1411. }
  1412. BOOL result = selectTabPanel(panel);
  1413. return result;
  1414. }
  1415. BOOL LLTabContainer::getTabPanelFlashing(LLPanel *child)
  1416. {
  1417. LLTabTuple* tuple = getTabByPanel(child);
  1418. if( tuple )
  1419. {
  1420. return tuple->mButton->getFlashing();
  1421. }
  1422. return FALSE;
  1423. }
  1424. void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state )
  1425. {
  1426. LLTabTuple* tuple = getTabByPanel(child);
  1427. if( tuple )
  1428. {
  1429. tuple->mButton->setFlashing( state );
  1430. }
  1431. }
  1432. void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color)
  1433. {
  1434. LLTabTuple* tuple = getTabByPanel(child);
  1435. if( tuple )
  1436. {
  1437. tuple->mButton->setImageOverlay(image_name, LLFontGL::LEFT, color);
  1438. reshapeTuple(tuple);
  1439. }
  1440. }
  1441. void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const LLColor4& color)
  1442. {
  1443. LLTabTuple* tuple = getTabByPanel(child);
  1444. if( tuple )
  1445. {
  1446. tuple->mButton->setImageOverlay(image_id, LLFontGL::LEFT, color);
  1447. reshapeTuple(tuple);
  1448. }
  1449. }
  1450. void LLTabContainer::setTabImage(LLPanel* child, LLIconCtrl* icon)
  1451. {
  1452. LLTabTuple* tuple = getTabByPanel(child);
  1453. LLCustomButtonIconCtrl* button;
  1454. if(tuple)
  1455. {
  1456. button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton);
  1457. if(button)
  1458. {
  1459. button->setIcon(icon);
  1460. reshapeTuple(tuple);
  1461. }
  1462. }
  1463. }
  1464. void LLTabContainer::reshapeTuple(LLTabTuple* tuple)
  1465. {
  1466. static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
  1467. if (!mIsVertical)
  1468. {
  1469. S32 image_overlay_width = 0;
  1470. if(mCustomIconCtrlUsed)
  1471. {
  1472. LLCustomButtonIconCtrl* button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton);
  1473. LLIconCtrl* icon_ctrl = button ? button->getIconCtrl() : NULL;
  1474. image_overlay_width = icon_ctrl ? icon_ctrl->getRect().getWidth() : 0;
  1475. }
  1476. else
  1477. {
  1478. image_overlay_width = tuple->mButton->getImageOverlay().notNull() ?
  1479. tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : 0;
  1480. }
  1481. // remove current width from total tab strip width
  1482. mTotalTabWidth -= tuple->mButton->getRect().getWidth();
  1483. tuple->mPadding = image_overlay_width;
  1484. tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),
  1485. tuple->mButton->getRect().getHeight());
  1486. // add back in button width to total tab strip width
  1487. mTotalTabWidth += tuple->mButton->getRect().getWidth();
  1488. // tabs have changed size, might need to scroll to see current tab
  1489. updateMaxScrollPos();
  1490. }
  1491. }
  1492. void LLTabContainer::setTitle(const std::string& title)
  1493. {
  1494. if (mTitleBox)
  1495. {
  1496. mTitleBox->setText( title );
  1497. }
  1498. }
  1499. const std::string LLTabContainer::getPanelTitle(S32 index)
  1500. {
  1501. if (index >= 0 && index < (S32)mTabList.size())
  1502. {
  1503. LLButton* tab_button = mTabList[index]->mButton;
  1504. return tab_button->getLabelSelected();
  1505. }
  1506. return LLStringUtil::null;
  1507. }
  1508. void LLTabContainer::setTopBorderHeight(S32 height)
  1509. {
  1510. mTopBorderHeight = height;
  1511. }
  1512. S32 LLTabContainer::getTopBorderHeight() const
  1513. {
  1514. return mTopBorderHeight;
  1515. }
  1516. void LLTabContainer::setRightTabBtnOffset(S32 offset)
  1517. {
  1518. mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 );
  1519. mRightTabBtnOffset = offset;
  1520. updateMaxScrollPos();
  1521. }
  1522. void LLTabContainer::setPanelTitle(S32 index, const std::string& title)
  1523. {
  1524. static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
  1525. if (index >= 0 && index < getTabCount())
  1526. {
  1527. LLTabTuple* tuple = getTab(index);
  1528. LLButton* tab_button = tuple->mButton;
  1529. const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
  1530. mTotalTabWidth -= tab_button->getRect().getWidth();
  1531. tab_button->reshape(llclamp(fontp->getWidth(title) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight());
  1532. mTotalTabWidth += tab_button->getRect().getWidth();
  1533. tab_button->setLabelSelected(title);
  1534. tab_button->setLabelUnselected(title);
  1535. }
  1536. updateMaxScrollPos();
  1537. }
  1538. void LLTabContainer::onTabBtn( const LLSD& data, LLPanel* panel )
  1539. {
  1540. LLTabTuple* tuple = getTabByPanel(panel);
  1541. selectTabPanel( panel );
  1542. if (tuple)
  1543. {
  1544. tuple->mTabPanel->setFocus(TRUE);
  1545. }
  1546. }
  1547. void LLTabContainer::onNextBtn( const LLSD& data )
  1548. {
  1549. if (!mScrolled)
  1550. {
  1551. scrollNext();
  1552. }
  1553. mScrolled = FALSE;
  1554. }
  1555. void LLTabContainer::onNextBtnHeld( const LLSD& data )
  1556. {
  1557. if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
  1558. {
  1559. mScrollTimer.reset();
  1560. scrollNext();
  1561. mScrolled = TRUE;
  1562. }
  1563. }
  1564. void LLTabContainer::onPrevBtn( const LLSD& data )
  1565. {
  1566. if (!mScrolled)
  1567. {
  1568. scrollPrev();
  1569. }
  1570. mScrolled = FALSE;
  1571. }
  1572. void LLTabContainer::onJumpFirstBtn( const LLSD& data )
  1573. {
  1574. mScrollPos = 0;
  1575. }
  1576. void LLTabContainer::onJumpLastBtn( const LLSD& data )
  1577. {
  1578. mScrollPos = mMaxScrollPos;
  1579. }
  1580. void LLTabContainer::onPrevBtnHeld( const LLSD& data )
  1581. {
  1582. if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
  1583. {
  1584. mScrollTimer.reset();
  1585. scrollPrev();
  1586. mScrolled = TRUE;
  1587. }
  1588. }
  1589. // private
  1590. void LLTabContainer::initButtons()
  1591. {
  1592. // Hack:
  1593. if (getRect().getHeight() == 0 || mPrevArrowBtn)
  1594. {
  1595. return; // Don't have a rect yet or already got called
  1596. }
  1597. if (mIsVertical)
  1598. {
  1599. static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
  1600. // Left and right scroll arrows (for when there are too many tabs to show all at once).
  1601. S32 btn_top = getRect().getHeight();
  1602. S32 btn_top_lower = getRect().mBottom+tabcntrv_arrow_btn_size;
  1603. LLRect up_arrow_btn_rect;
  1604. up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size );
  1605. LLRect down_arrow_btn_rect;
  1606. down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size );
  1607. LLButton::Params prev_btn_params;
  1608. prev_btn_params.name(std::string("Up Arrow"));
  1609. prev_btn_params.rect(up_arrow_btn_rect);
  1610. prev_btn_params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
  1611. prev_btn_params.image_unselected.name("scrollbutton_up_out_blue.tga");
  1612. prev_btn_params.image_selected.name("scrollbutton_up_in_blue.tga");
  1613. prev_btn_params.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2));
  1614. mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(prev_btn_params);
  1615. LLButton::Params next_btn_params;
  1616. next_btn_params.name(std::string("Down Arrow"));
  1617. next_btn_params.rect(down_arrow_btn_rect);
  1618. next_btn_params.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_LEFT);
  1619. next_btn_params.image_unselected.name("scrollbutton_down_out_blue.tga");
  1620. next_btn_params.image_selected.name("scrollbutton_down_in_blue.tga");
  1621. next_btn_params.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2));
  1622. mNextArrowBtn = LLUICtrlFactory::create<LLButton>(next_btn_params);
  1623. }
  1624. else // Horizontal
  1625. {
  1626. static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
  1627. S32 arrow_fudge = 1; // match new art better
  1628. // Left and right scroll arrows (for when there are too many tabs to show all at once).
  1629. S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : tabcntr_arrow_btn_size + 1;
  1630. LLRect left_arrow_btn_rect;
  1631. left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+tabcntr_arrow_btn_size, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight );
  1632. LLRect jump_left_arrow_btn_rect;
  1633. jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight );
  1634. S32 right_pad = tabcntr_arrow_btn_size + LLPANEL_BORDER_WIDTH + 1;
  1635. LLRect right_arrow_btn_rect;
  1636. right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - tabcntr_arrow_btn_size,
  1637. btn_top + arrow_fudge,
  1638. tabcntr_arrow_btn_size, mTabHeight );
  1639. LLRect jump_right_arrow_btn_rect;
  1640. jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad,
  1641. btn_top + arrow_fudge,
  1642. tabcntr_arrow_btn_size, mTabHeight );
  1643. LLButton::Params p;
  1644. p.name(std::string("Jump Left Arrow"));
  1645. p.image_unselected.name("jump_left_out.tga");
  1646. p.image_selected.name("jump_left_in.tga");
  1647. p.click_callback.function(boost::bind(&LLTabContainer::onJumpFirstBtn, this, _2));
  1648. p.rect(jump_left_arrow_btn_rect);
  1649. p.follows.flags(FOLLOWS_LEFT);
  1650. mJumpPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p);
  1651. p = LLButton::Params();
  1652. p.name(std::string("Left Arrow"));
  1653. p.rect(left_arrow_btn_rect);
  1654. p.follows.flags(FOLLOWS_LEFT);
  1655. p.image_unselected.name("scrollbutton_left_out_blue.tga");
  1656. p.image_selected.name("scrollbutton_left_in_blue.tga");
  1657. p.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2));
  1658. p.mouse_held_callback.function(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2));
  1659. mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p);
  1660. p = LLButton::Params();
  1661. p.name(std::string("Jump Right Arrow"));
  1662. p.rect(jump_right_arrow_btn_rect);
  1663. p.follows.flags(FOLLOWS_RIGHT);
  1664. p.image_unselected.name("jump_right_out.tga");
  1665. p.image_selected.name("jump_right_in.tga");
  1666. p.click_callback.function(boost::bind(&LLTabContainer::onJumpLastBtn, this, _2));
  1667. mJumpNextArrowBtn = LLUICtrlFactory::create<LLButton>(p);
  1668. p = LLButton::Params();
  1669. p.name(std::string("Right Arrow"));
  1670. p.rect(right_arrow_btn_rect);
  1671. p.follows.flags(FOLLOWS_RIGHT);
  1672. p.image_unselected.name("scrollbutton_right_out_blue.tga");
  1673. p.image_selected.name("scrollbutton_right_in_blue.tga");
  1674. p.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2));
  1675. p.mouse_held_callback.function(boost::bind(&LLTabContainer::onNextBtnHeld, this, _2));
  1676. mNextArrowBtn = LLUICtrlFactory::create<LLButton>(p);
  1677. if( getTabPosition() == TOP )
  1678. {
  1679. mNextArrowBtn->setFollowsTop();
  1680. mPrevArrowBtn->setFollowsTop();
  1681. mJumpPrevArrowBtn->setFollowsTop();
  1682. mJumpNextArrowBtn->setFollowsTop();
  1683. }
  1684. else
  1685. {
  1686. mNextArrowBtn->setFollowsBottom();
  1687. mPrevArrowBtn->setFollowsBottom();
  1688. mJumpPrevArrowBtn->setFollowsBottom();
  1689. mJumpNextArrowBtn->setFollowsBottom();
  1690. }
  1691. }
  1692. mPrevArrowBtn->setTabStop(FALSE);
  1693. addChild(mPrevArrowBtn);
  1694. mNextArrowBtn->setTabStop(FALSE);
  1695. addChild(mNextArrowBtn);
  1696. if (mJumpPrevArrowBtn)
  1697. {
  1698. mJumpPrevArrowBtn->setTabStop(FALSE);
  1699. addChild(mJumpPrevArrowBtn);
  1700. }
  1701. if (mJumpNextArrowBtn)
  1702. {
  1703. mJumpNextArrowBtn->setTabStop(FALSE);
  1704. addChild(mJumpNextArrowBtn);
  1705. }
  1706. // set default tab group to be panel contents
  1707. setDefaultTabGroup(1);
  1708. }
  1709. //this is a work around for the current LLPanel::initFromParams hack
  1710. //so that it doesn't overwrite the default tab group.
  1711. //will be removed when LLPanel is fixed soon.
  1712. void LLTabContainer::initFromParams(const LLPanel::Params& p)
  1713. {
  1714. LLPanel::initFromParams(p);
  1715. setDefaultTabGroup(1);
  1716. }
  1717. LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child)
  1718. {
  1719. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1720. {
  1721. LLTabTuple* tuple = *iter;
  1722. if( tuple->mTabPanel == child )
  1723. {
  1724. return tuple;
  1725. }
  1726. }
  1727. return NULL;
  1728. }
  1729. void LLTabContainer::insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point)
  1730. {
  1731. switch(insertion_point)
  1732. {
  1733. case START:
  1734. // insert the new tab in the front of the list
  1735. mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
  1736. break;
  1737. case LEFT_OF_CURRENT:
  1738. // insert the new tab before the current tab (but not before mLockedTabCount)
  1739. {
  1740. tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx);
  1741. mTabList.insert(current_iter, tuple);
  1742. }
  1743. break;
  1744. case RIGHT_OF_CURRENT:
  1745. // insert the new tab after the current tab (but not before mLockedTabCount)
  1746. {
  1747. tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1);
  1748. mTabList.insert(current_iter, tuple);
  1749. }
  1750. break;
  1751. case END:
  1752. default:
  1753. mTabList.push_back( tuple );
  1754. }
  1755. }
  1756. void LLTabContainer::updateMaxScrollPos()
  1757. {
  1758. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  1759. BOOL no_scroll = TRUE;
  1760. if (mIsVertical)
  1761. {
  1762. S32 tab_total_height = (BTN_HEIGHT + tabcntrv_pad) * getTabCount();
  1763. S32 available_height = getRect().getHeight() - getTopBorderHeight();
  1764. if( tab_total_height > available_height )
  1765. {
  1766. static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
  1767. S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad);
  1768. S32 additional_needed = tab_total_height - available_height_with_arrows;
  1769. setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) );
  1770. no_scroll = FALSE;
  1771. }
  1772. }
  1773. else
  1774. {
  1775. static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0);
  1776. static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
  1777. static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0);
  1778. S32 tab_space = 0;
  1779. S32 available_space = 0;
  1780. tab_space = mTotalTabWidth;
  1781. available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_tab_h_pad);
  1782. if( tab_space > available_space )
  1783. {
  1784. S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1);
  1785. // subtract off reserved portion on left
  1786. available_width_with_arrows -= tabcntr_tab_partial_width;
  1787. S32 running_tab_width = 0;
  1788. setMaxScrollPos(getTabCount());
  1789. for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it)
  1790. {
  1791. running_tab_width += (*tab_it)->mButton->getRect().getWidth();
  1792. if (running_tab_width > available_width_with_arrows)
  1793. {
  1794. break;
  1795. }
  1796. setMaxScrollPos(getMaxScrollPos()-1);
  1797. }
  1798. // in case last tab doesn't actually fit on screen, make it the last scrolling position
  1799. setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1));
  1800. no_scroll = FALSE;
  1801. }
  1802. }
  1803. if (no_scroll)
  1804. {
  1805. setMaxScrollPos(0);
  1806. setScrollPos(0);
  1807. }
  1808. if (getScrollPos() > getMaxScrollPos())
  1809. {
  1810. setScrollPos(getMaxScrollPos()); // maybe just enforce this via limits in setScrollPos instead?
  1811. }
  1812. }
  1813. void LLTabContainer::commitHoveredButton(S32 x, S32 y)
  1814. {
  1815. if (!getTabsHidden() && hasMouseCapture())
  1816. {
  1817. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1818. {
  1819. LLTabTuple* tuple = *iter;
  1820. S32 local_x = x - tuple->mButton->getRect().mLeft;
  1821. S32 local_y = y - tuple->mButton->getRect().mBottom;
  1822. if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
  1823. {
  1824. tuple->mButton->onCommit();
  1825. }
  1826. }
  1827. }
  1828. }