lltabcontainer.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:55k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lltabcontainer.cpp
  3.  * @brief LLTabContainer class
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #include "lltabcontainer.h"
  34. #include "llfocusmgr.h"
  35. #include "lllocalcliprect.h"
  36. #include "llrect.h"
  37. #include "llresizehandle.h"
  38. #include "lltextbox.h"
  39. #include "llcriticaldamp.h"
  40. #include "lluictrlfactory.h"
  41. #include "llrender.h"
  42. #include "llfloater.h"
  43. #include "lltrans.h"
  44. //----------------------------------------------------------------------------
  45. // Implementation Notes:
  46. //  - Each tab points to a LLPanel (see LLTabTuple below)
  47. //  - When a tab is selected, the validation callback
  48. //    (LLUICtrl::mValidateSignal) is called
  49. //  -  If the validation callback returns true (or none is provided),
  50. //     the tab is changed and the commit callback
  51. //     (LLUICtrl::mCommitSignal) is called
  52. //  - Callbacks pass the LLTabContainer as the control,
  53. //    and the NAME of the selected PANEL as the LLSD data
  54. //----------------------------------------------------------------------------
  55. const F32 SCROLL_STEP_TIME = 0.4f;
  56. const F32 SCROLL_DELAY_TIME = 0.5f;
  57. void LLTabContainer::TabPositions::declareValues()
  58. {
  59. declare("top", LLTabContainer::TOP);
  60. declare("bottom", LLTabContainer::BOTTOM);
  61. declare("left", LLTabContainer::LEFT);
  62. }
  63. //----------------------------------------------------------------------------
  64. // Structure used to map tab buttons to and from tab panels
  65. class LLTabTuple
  66. {
  67. public:
  68. LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, LLTextBox* placeholder = NULL)
  69. :
  70. mTabContainer(c),
  71. mTabPanel(p),
  72. mButton(b),
  73. mOldState(FALSE),
  74. mPlaceholderText(placeholder),
  75. mPadding(0)
  76. {}
  77. LLTabContainer*  mTabContainer;
  78. LLPanel*  mTabPanel;
  79. LLButton*  mButton;
  80. BOOL  mOldState;
  81. LLTextBox*  mPlaceholderText;
  82. S32  mPadding;
  83. };
  84. //----------------------------------------------------------------------------
  85. //============================================================================
  86. /*
  87.  * @file lltabcontainer.cpp
  88.  * @brief class implements LLButton with LLIconCtrl on it
  89.  */
  90. class LLCustomButtonIconCtrl : public LLButton
  91. {
  92. public:
  93. struct Params
  94. : public LLInitParam::Block<Params, LLButton::Params>
  95. {
  96. // LEFT, RIGHT, TOP, BOTTOM paddings of LLIconCtrl in this class has same value
  97. Optional<S32> icon_ctrl_pad;
  98. Params():
  99. icon_ctrl_pad("icon_ctrl_pad", 1)
  100. {}
  101. };
  102. protected:
  103. friend class LLUICtrlFactory;
  104. LLCustomButtonIconCtrl(const Params& p):
  105. LLButton(p),
  106. mIcon(NULL),
  107. mIconAlignment(LLFontGL::HCENTER),
  108. mIconCtrlPad(p.icon_ctrl_pad)
  109. {}
  110. public:
  111. void updateLayout()
  112. {
  113. LLRect button_rect = getRect();
  114. LLRect icon_rect = mIcon->getRect();
  115. S32 icon_size = button_rect.getHeight() - 2*mIconCtrlPad;
  116. switch(mIconAlignment)
  117. {
  118. case LLFontGL::LEFT:
  119. icon_rect.setLeftTopAndSize(button_rect.mLeft + mIconCtrlPad, button_rect.mTop - mIconCtrlPad, 
  120. icon_size, icon_size);
  121. setLeftHPad(icon_size + mIconCtrlPad * 2);
  122. break;
  123. case LLFontGL::HCENTER:
  124. icon_rect.setLeftTopAndSize(button_rect.mRight - (button_rect.getWidth() + mIconCtrlPad - icon_size)/2, button_rect.mTop - mIconCtrlPad, 
  125. icon_size, icon_size);
  126. setRightHPad(icon_size + mIconCtrlPad * 2);
  127. break;
  128. case LLFontGL::RIGHT:
  129. icon_rect.setLeftTopAndSize(button_rect.mRight - mIconCtrlPad - icon_size, button_rect.mTop - mIconCtrlPad, 
  130. icon_size, icon_size);
  131. setRightHPad(icon_size + mIconCtrlPad * 2);
  132. break;
  133. default:
  134. break;
  135. }
  136. mIcon->setRect(icon_rect);
  137. }
  138. void setIcon(LLIconCtrl* icon, LLFontGL::HAlign alignment = LLFontGL::LEFT)
  139. {
  140. if(icon)
  141. {
  142. if(mIcon)
  143. {
  144. removeChild(mIcon);
  145. mIcon->die();
  146. }
  147. mIcon = icon;
  148. mIconAlignment = alignment;
  149. addChild(mIcon);
  150. updateLayout();
  151. }
  152. }
  153. private:
  154. LLIconCtrl* mIcon;
  155. LLFontGL::HAlign mIconAlignment;
  156. S32 mIconCtrlPad;
  157. };
  158. //============================================================================
  159. struct LLPlaceHolderPanel : public LLPanel
  160. {
  161. // create dummy param block to register with "placeholder" nane
  162. struct Params : public LLPanel::Params{};
  163. LLPlaceHolderPanel(const Params& p) : LLPanel(p)
  164. {}
  165. };
  166. static LLDefaultChildRegistry::Register<LLPlaceHolderPanel> r1("placeholder");
  167. static LLDefaultChildRegistry::Register<LLTabContainer> r2("tab_container");
  168. LLTabContainer::TabParams::TabParams()
  169. : tab_top_image_unselected("tab_top_image_unselected"),
  170. tab_top_image_selected("tab_top_image_selected"),
  171. tab_bottom_image_unselected("tab_bottom_image_unselected"),
  172. tab_bottom_image_selected("tab_bottom_image_selected"),
  173. tab_left_image_unselected("tab_left_image_unselected"),
  174. tab_left_image_selected("tab_left_image_selected")
  175. {}
  176. LLTabContainer::Params::Params()
  177. : tab_width("tab_width"),
  178. tab_min_width("tab_min_width"),
  179. tab_max_width("tab_max_width"),
  180. tab_height("tab_height"),
  181. label_pad_bottom("label_pad_bottom"),
  182. label_pad_left("label_pad_left"),
  183. tab_position("tab_position"),
  184. hide_tabs("hide_tabs", false),
  185. tab_padding_right("tab_padding_right"),
  186. first_tab("first_tab"),
  187. middle_tab("middle_tab"),
  188. last_tab("last_tab"),
  189. use_custom_icon_ctrl("use_custom_icon_ctrl", false),
  190. tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0),
  191. use_ellipses("use_ellipses"),
  192. font_halign("font_halign")
  193. {
  194. name(std::string("tab_container"));
  195. mouse_opaque = false;
  196. }
  197. LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
  198. : LLPanel(p),
  199. mCurrentTabIdx(-1),
  200. mTabsHidden(p.hide_tabs),
  201. mScrolled(FALSE),
  202. mScrollPos(0),
  203. mScrollPosPixels(0),
  204. mMaxScrollPos(0),
  205. mTitleBox(NULL),
  206. mTopBorderHeight(LLPANEL_BORDER_WIDTH),
  207. mLockedTabCount(0),
  208. mMinTabWidth(0),
  209. mMaxTabWidth(p.tab_max_width),
  210. mTabHeight(p.tab_height),
  211. mLabelPadBottom(p.label_pad_bottom),
  212. mLabelPadLeft(p.label_pad_left),
  213. mPrevArrowBtn(NULL),
  214. mNextArrowBtn(NULL),
  215. mIsVertical( p.tab_position == LEFT ),
  216. // Horizontal Specific
  217. mJumpPrevArrowBtn(NULL),
  218. mJumpNextArrowBtn(NULL),
  219. mRightTabBtnOffset(p.tab_padding_right),
  220. mTotalTabWidth(0),
  221. mTabPosition(p.tab_position),
  222. mFontHalign(p.font_halign),
  223. mFont(p.font),
  224. mFirstTabParams(p.first_tab),
  225. mMiddleTabParams(p.middle_tab),
  226. mLastTabParams(p.last_tab),
  227. mCustomIconCtrlUsed(p.use_custom_icon_ctrl),
  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.pushMatrix();
  442. gGL.translatef((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f);
  443. mPrevArrowBtn->draw();
  444. gGL.popMatrix();
  445. gGL.pushMatrix();
  446. gGL.translatef((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f);
  447. mNextArrowBtn->draw();
  448. gGL.popMatrix();
  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)
  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) 
  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( mDragAndDropDelayTimer.getStarted() && mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME )
  743. {
  744. if (has_scroll_arrows)
  745. {
  746. if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y))
  747. {
  748. S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
  749. S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
  750. mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
  751. }
  752. if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y))
  753. {
  754. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  755. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  756. mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
  757. }
  758. if (mPrevArrowBtn->getRect().pointInRect(x, y))
  759. {
  760. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  761. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  762. mPrevArrowBtn->handleHover(local_x, local_y, mask);
  763. }
  764. else if (mNextArrowBtn->getRect().pointInRect(x, y))
  765. {
  766. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  767. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  768. mNextArrowBtn->handleHover(local_x, local_y, mask);
  769. }
  770. }
  771. for(tuple_list_t::iterator iter = mTabList.begin(); iter !=  mTabList.end(); ++iter)
  772. {
  773. LLTabTuple* tuple = *iter;
  774. tuple->mButton->setVisible( TRUE );
  775. S32 local_x = x - tuple->mButton->getRect().mLeft;
  776. S32 local_y = y - tuple->mButton->getRect().mBottom;
  777. if (tuple->mButton->pointInView(local_x, local_y) &&  tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
  778. {
  779. tuple->mButton->onCommit();
  780. mDragAndDropDelayTimer.stop();
  781. }
  782. }
  783. }
  784. return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data,  accept, tooltip);
  785. }
  786. void LLTabContainer::addTabPanel(LLPanel* panelp)
  787. {
  788. addTabPanel(TabPanelParams().panel(panelp));
  789. }
  790. // function to update images
  791. void LLTabContainer::update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos)
  792. {
  793. if (tuple && tuple->mButton)
  794. {
  795. if (pos == LLTabContainer::TOP)
  796. {
  797. tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_top_image_unselected));
  798. tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_top_image_selected));
  799. }
  800. else if (pos == LLTabContainer::BOTTOM)
  801. {
  802. tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_bottom_image_unselected));
  803. tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_bottom_image_selected));
  804. }
  805. else if (pos == LLTabContainer::LEFT)
  806. {
  807. tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_left_image_unselected));
  808. tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_left_image_selected));
  809. }
  810. }
  811. }
  812. void LLTabContainer::addTabPanel(const TabPanelParams& panel)
  813. {
  814. LLPanel* child = panel.panel();
  815. llassert(child);
  816. if (!child) return;
  817. const std::string& label = panel.label.isProvided() 
  818. ? panel.label() 
  819. : panel.panel()->getLabel();
  820. BOOL select = panel.select_tab(); 
  821. S32 indent = panel.indent();
  822. BOOL placeholder = panel.is_placeholder;
  823. eInsertionPoint insertion_point = panel.insert_at();
  824. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  825. static LLUICachedControl<S32> tabcntr_button_panel_overlap ("UITabCntrButtonPanelOverlap", 0);
  826. static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
  827. if (child->getParent() == this)
  828. {
  829. // already a child of mine
  830. return;
  831. }
  832. // Store the original label for possible xml export.
  833. child->setLabel(label);
  834. std::string trimmed_label = label;
  835. LLStringUtil::trim(trimmed_label);
  836. S32 button_width = mMinTabWidth;
  837. if (!mIsVertical)
  838. {
  839. button_width = llclamp(mFont->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth);
  840. }
  841. // Tab panel
  842. S32 tab_panel_top;
  843. S32 tab_panel_bottom;
  844. if (!getTabsHidden()) 
  845. {
  846. if( getTabPosition() == LLTabContainer::TOP )
  847. {
  848. S32 tab_height = mIsVertical ? BTN_HEIGHT : mTabHeight;
  849. tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - tabcntr_button_panel_overlap);
  850. tab_panel_bottom = LLPANEL_BORDER_WIDTH;
  851. }
  852. else
  853. {
  854. tab_panel_top = getRect().getHeight() - getTopBorderHeight();
  855. tab_panel_bottom = (mTabHeight - tabcntr_button_panel_overlap);  // Run to the edge, covering up the border
  856. }
  857. }
  858. else
  859. {
  860. //Scip tab button space if they are invisible(EXT - 576)
  861. tab_panel_top = getRect().getHeight();
  862. tab_panel_bottom = LLPANEL_BORDER_WIDTH;
  863. }
  864. LLRect tab_panel_rect;
  865. if (!getTabsHidden() && mIsVertical)
  866. {
  867. tab_panel_rect = LLRect(mMinTabWidth + (LLPANEL_BORDER_WIDTH * 2) + tabcntrv_pad, 
  868. getRect().getHeight() - LLPANEL_BORDER_WIDTH,
  869. getRect().getWidth() - LLPANEL_BORDER_WIDTH,
  870. LLPANEL_BORDER_WIDTH);
  871. }
  872. else
  873. {
  874. tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH, 
  875. tab_panel_top,
  876. getRect().getWidth()-LLPANEL_BORDER_WIDTH,
  877. tab_panel_bottom );
  878. }
  879. child->setFollowsAll();
  880. child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
  881. child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
  882. // add this child later
  883. child->setVisible( FALSE );  // Will be made visible when selected
  884. mTotalTabWidth += button_width;
  885. // Tab button
  886. LLRect btn_rect;  // Note: btn_rect.mLeft is just a dummy.  Will be updated in draw().
  887. LLUIImage* tab_img = NULL;
  888. LLUIImage* tab_selected_img = NULL;
  889. S32 tab_fudge = 1; //  To make new tab art look better, nudge buttons up 1 pel
  890. if (mIsVertical)
  891. {
  892. btn_rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
  893.    (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * getTabCount()),
  894.    mMinTabWidth,
  895.    BTN_HEIGHT);
  896. }
  897. else if( getTabPosition() == LLTabContainer::TOP )
  898. {
  899. btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, mTabHeight);
  900. tab_img = mMiddleTabParams.tab_top_image_unselected;
  901. tab_selected_img = mMiddleTabParams.tab_top_image_selected; 
  902. }
  903. else
  904. {
  905. btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, mTabHeight);
  906. tab_img = mMiddleTabParams.tab_bottom_image_unselected;
  907. tab_selected_img = mMiddleTabParams.tab_bottom_image_selected;
  908. }
  909. LLTextBox* textbox = NULL;
  910. LLButton* btn = NULL;
  911. LLCustomButtonIconCtrl::Params custom_btn_params;
  912. {
  913. custom_btn_params.icon_ctrl_pad(mTabIconCtrlPad);
  914. }
  915. LLButton::Params normal_btn_params;
  916. if (placeholder)
  917. {
  918. btn_rect.translate(0, -6); // *TODO: make configurable
  919. LLTextBox::Params params;
  920. params.name(trimmed_label);
  921. params.rect(btn_rect);
  922. params.initial_value(trimmed_label);
  923. params.font(mFont);
  924. textbox = LLUICtrlFactory::create<LLTextBox> (params);
  925. LLButton::Params p;
  926. p.name("placeholder");
  927. btn = LLUICtrlFactory::create<LLButton>(p);
  928. }
  929. else
  930. {
  931. if (mIsVertical)
  932. {
  933. LLButton::Params& p = (mCustomIconCtrlUsed)?
  934. custom_btn_params:normal_btn_params;
  935. p.name(std::string("vert tab button"));
  936. p.rect(btn_rect);
  937. p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
  938. p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
  939. p.font(mFont);
  940. p.label(trimmed_label);
  941. p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
  942. p.image_selected(mMiddleTabParams.tab_left_image_selected);
  943. p.scale_image(true);
  944. p.font_halign = mFontHalign;
  945. p.pad_bottom( mLabelPadBottom );
  946. p.tab_stop(false);
  947. p.label_shadow(false);
  948. if (indent)
  949. {
  950. p.pad_left(indent);
  951. }
  952. if(mCustomIconCtrlUsed)
  953. {
  954. btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params);
  955. }
  956. else
  957. {
  958. btn = LLUICtrlFactory::create<LLButton>(p);
  959. }
  960. }
  961. else
  962. {
  963. LLButton::Params& p = (mCustomIconCtrlUsed)?
  964. custom_btn_params:normal_btn_params;
  965. p.name(std::string(child->getName()) + " tab");
  966. p.rect(btn_rect);
  967. p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
  968. p.font(mFont);
  969. p.label(trimmed_label);
  970. p.visible(false);
  971. p.scale_image(true);
  972. p.image_unselected(tab_img);
  973. p.image_selected(tab_selected_img);
  974. p.tab_stop(false);
  975. p.label_shadow(false);
  976. // Try to squeeze in a bit more text
  977. p.pad_left( mLabelPadLeft );
  978. p.pad_right(2);
  979. p.pad_bottom( mLabelPadBottom );
  980. p.font_halign = mFontHalign;
  981. p.follows.flags = FOLLOWS_LEFT;
  982. p.follows.flags = FOLLOWS_LEFT;
  983. if (indent)
  984. {
  985. p.pad_left(indent);
  986. }
  987. if( getTabPosition() == TOP )
  988. {
  989. p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
  990. }
  991. else
  992. {
  993. p.follows.flags = p.follows.flags() | FOLLOWS_BOTTOM;
  994. }
  995. if(mCustomIconCtrlUsed)
  996. {
  997. btn = LLUICtrlFactory::create<LLCustomButtonIconCtrl>(custom_btn_params);
  998. }
  999. else
  1000. {
  1001. btn = LLUICtrlFactory::create<LLButton>(p);
  1002. }
  1003. }
  1004. }
  1005. LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox );
  1006. insertTuple( tuple, insertion_point );
  1007. // if new tab was added as a first or last tab, update button image 
  1008. // and update button image of any tab it may have affected
  1009. if (tuple == mTabList.front())
  1010. {  
  1011. update_images(tuple, mFirstTabParams, getTabPosition());
  1012. if (mTabList.size() == 2) 
  1013. {
  1014. update_images(mTabList[1], mLastTabParams, getTabPosition());
  1015. }
  1016. else if (mTabList.size() > 2) 
  1017. {
  1018. update_images(mTabList[1], mMiddleTabParams, getTabPosition());
  1019. }
  1020. }
  1021. else if (tuple == mTabList.back())
  1022. {
  1023. update_images(tuple, mLastTabParams, getTabPosition());
  1024. if (mTabList.size() > 2)
  1025. {
  1026. update_images(mTabList[mTabList.size()-2], mMiddleTabParams, getTabPosition());
  1027. }
  1028. }
  1029. //Don't add button and textbox if tab buttons are invisible(EXT - 576)
  1030. if (!getTabsHidden())
  1031. {
  1032. if (textbox)
  1033. {
  1034. addChild( textbox, 0 );
  1035. }
  1036. if (btn)
  1037. {
  1038. addChild( btn, 0 );
  1039. }
  1040. }
  1041. if (child)
  1042. {
  1043. LLUICtrl::addChild(child, 1);
  1044. }
  1045. sendChildToFront(mPrevArrowBtn);
  1046. sendChildToFront(mNextArrowBtn);
  1047. sendChildToFront(mJumpPrevArrowBtn);
  1048. sendChildToFront(mJumpNextArrowBtn);
  1049. if( select )
  1050. {
  1051. selectLastTab();
  1052. }
  1053. updateMaxScrollPos();
  1054. }
  1055. void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label)
  1056. {
  1057. addTabPanel(TabPanelParams().panel(child).label(label).is_placeholder(true));
  1058. }
  1059. void LLTabContainer::removeTabPanel(LLPanel* child)
  1060. {
  1061. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  1062. if (mIsVertical)
  1063. {
  1064. // Fix-up button sizes
  1065. S32 tab_count = 0;
  1066. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1067. {
  1068. LLTabTuple* tuple = *iter;
  1069. LLRect rect;
  1070. rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
  1071.    (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * (tab_count)),
  1072.    mMinTabWidth,
  1073.    BTN_HEIGHT);
  1074. if (tuple->mPlaceholderText)
  1075. {
  1076. tuple->mPlaceholderText->setRect(rect);
  1077. }
  1078. else
  1079. {
  1080. tuple->mButton->setRect(rect);
  1081. }
  1082. tab_count++;
  1083. }
  1084. }
  1085. else
  1086. {
  1087. // Adjust the total tab width.
  1088. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1089. {
  1090. LLTabTuple* tuple = *iter;
  1091. if( tuple->mTabPanel == child )
  1092. {
  1093. mTotalTabWidth -= tuple->mButton->getRect().getWidth();
  1094. break;
  1095. }
  1096. }
  1097. }
  1098. BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this);
  1099. // If the tab being deleted is the selected one, select a different tab.
  1100. for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1101. {
  1102. LLTabTuple* tuple = *iter;
  1103. if( tuple->mTabPanel == child )
  1104. {
  1105. // update tab button images if removing the first or last tab
  1106. if ((tuple == mTabList.front()) && (mTabList.size() > 1))
  1107. {
  1108. update_images(mTabList[1], mFirstTabParams, getTabPosition());
  1109. }
  1110. else if ((tuple == mTabList.back()) && (mTabList.size() > 2))
  1111. {
  1112. update_images(mTabList[mTabList.size()-2], mLastTabParams, getTabPosition());
  1113. }
  1114. removeChild( tuple->mButton );
  1115.   delete tuple->mButton;
  1116.   removeChild( tuple->mTabPanel );
  1117. //  delete tuple->mTabPanel;
  1118. mTabList.erase( iter );
  1119. delete tuple;
  1120. break;
  1121. }
  1122. }
  1123. // make sure we don't have more locked tabs than we have tabs
  1124. mLockedTabCount = llmin(getTabCount(), mLockedTabCount);
  1125. if (mCurrentTabIdx >= (S32)mTabList.size())
  1126. {
  1127. mCurrentTabIdx = mTabList.size()-1;
  1128. }
  1129. selectTab(mCurrentTabIdx);
  1130. if (has_focus)
  1131. {
  1132. LLPanel* panelp = getPanelByIndex(mCurrentTabIdx);
  1133. if (panelp)
  1134. {
  1135. panelp->setFocus(TRUE);
  1136. }
  1137. }
  1138. updateMaxScrollPos();
  1139. }
  1140. void LLTabContainer::lockTabs(S32 num_tabs)
  1141. {
  1142. // count current tabs or use supplied value and ensure no new tabs get
  1143. // inserted between them
  1144. mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount();
  1145. }
  1146. void LLTabContainer::unlockTabs()
  1147. {
  1148. mLockedTabCount = 0;
  1149. }
  1150. void LLTabContainer::enableTabButton(S32 which, BOOL enable)
  1151. {
  1152. if (which >= 0 && which < (S32)mTabList.size())
  1153. {
  1154. mTabList[which]->mButton->setEnabled(enable);
  1155. }
  1156. }
  1157. void LLTabContainer::deleteAllTabs()
  1158. {
  1159. // Remove all the tab buttons and delete them.  Also, unlink all the child panels.
  1160. for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1161. {
  1162. LLTabTuple* tuple = *iter;
  1163. removeChild( tuple->mButton );
  1164. delete tuple->mButton;
  1165.   removeChild( tuple->mTabPanel );
  1166. //  delete tuple->mTabPanel;
  1167. }
  1168. // Actually delete the tuples themselves
  1169. std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
  1170. mTabList.clear();
  1171. // And there isn't a current tab any more
  1172. mCurrentTabIdx = -1;
  1173. }
  1174. LLPanel* LLTabContainer::getCurrentPanel()
  1175. {
  1176. if (mCurrentTabIdx >= 0 && mCurrentTabIdx < (S32) mTabList.size())
  1177. {
  1178. return mTabList[mCurrentTabIdx]->mTabPanel;
  1179. }
  1180. return NULL;
  1181. }
  1182. S32 LLTabContainer::getCurrentPanelIndex()
  1183. {
  1184. return mCurrentTabIdx;
  1185. }
  1186. S32 LLTabContainer::getTabCount()
  1187. {
  1188. return mTabList.size();
  1189. }
  1190. LLPanel* LLTabContainer::getPanelByIndex(S32 index)
  1191. {
  1192. if (index >= 0 && index < (S32)mTabList.size())
  1193. {
  1194. return mTabList[index]->mTabPanel;
  1195. }
  1196. return NULL;
  1197. }
  1198. S32 LLTabContainer::getIndexForPanel(LLPanel* panel)
  1199. {
  1200. for (S32 index = 0; index < (S32)mTabList.size(); index++)
  1201. {
  1202. if (mTabList[index]->mTabPanel == panel)
  1203. {
  1204. return index;
  1205. }
  1206. }
  1207. return -1;
  1208. }
  1209. S32 LLTabContainer::getPanelIndexByTitle(const std::string& title)
  1210. {
  1211. for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
  1212. {
  1213. if (title == mTabList[index]->mButton->getLabelSelected())
  1214. {
  1215. return index;
  1216. }
  1217. }
  1218. return -1;
  1219. }
  1220. LLPanel* LLTabContainer::getPanelByName(const std::string& name)
  1221. {
  1222. for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
  1223. {
  1224. LLPanel *panel = mTabList[index]->mTabPanel;
  1225. if (name == panel->getName())
  1226. {
  1227. return panel;
  1228. }
  1229. }
  1230. return NULL;
  1231. }
  1232. // Change the name of the button for the current tab.
  1233. void LLTabContainer::setCurrentTabName(const std::string& name)
  1234. {
  1235. // Might not have a tab selected
  1236. if (mCurrentTabIdx < 0) return;
  1237. mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name);
  1238. mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name);
  1239. }
  1240. void LLTabContainer::selectFirstTab()
  1241. {
  1242. selectTab( 0 );
  1243. }
  1244. void LLTabContainer::selectLastTab()
  1245. {
  1246. selectTab( mTabList.size()-1 );
  1247. }
  1248. void LLTabContainer::selectNextTab()
  1249. {
  1250. BOOL tab_has_focus = FALSE;
  1251. if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
  1252. {
  1253. tab_has_focus = TRUE;
  1254. }
  1255. S32 idx = mCurrentTabIdx+1;
  1256. if (idx >= (S32)mTabList.size())
  1257. idx = 0;
  1258. while (!selectTab(idx) && idx != mCurrentTabIdx)
  1259. {
  1260. idx = (idx + 1 ) % (S32)mTabList.size();
  1261. }
  1262. if (tab_has_focus)
  1263. {
  1264. mTabList[idx]->mButton->setFocus(TRUE);
  1265. }
  1266. }
  1267. void LLTabContainer::selectPrevTab()
  1268. {
  1269. BOOL tab_has_focus = FALSE;
  1270. if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
  1271. {
  1272. tab_has_focus = TRUE;
  1273. }
  1274. S32 idx = mCurrentTabIdx-1;
  1275. if (idx < 0)
  1276. idx = mTabList.size()-1;
  1277. while (!selectTab(idx) && idx != mCurrentTabIdx)
  1278. {
  1279. idx = idx - 1;
  1280. if (idx < 0)
  1281. idx = mTabList.size()-1;
  1282. }
  1283. if (tab_has_focus)
  1284. {
  1285. mTabList[idx]->mButton->setFocus(TRUE);
  1286. }
  1287. }
  1288. BOOL LLTabContainer::selectTabPanel(LLPanel* child)
  1289. {
  1290. S32 idx = 0;
  1291. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1292. {
  1293. LLTabTuple* tuple = *iter;
  1294. if( tuple->mTabPanel == child )
  1295. {
  1296. return selectTab( idx );
  1297. }
  1298. idx++;
  1299. }
  1300. return FALSE;
  1301. }
  1302. BOOL LLTabContainer::selectTab(S32 which)
  1303. {
  1304. if (which >= getTabCount() || which < 0)
  1305. return FALSE;
  1306. LLTabTuple* selected_tuple = getTab(which);
  1307. if (!selected_tuple)
  1308. {
  1309. return FALSE;
  1310. }
  1311. LLSD cbdata;
  1312. if (selected_tuple->mTabPanel)
  1313. cbdata = selected_tuple->mTabPanel->getName();
  1314. BOOL res = FALSE;
  1315. if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) )
  1316. {
  1317. res = setTab(which);
  1318. if (res && mCommitSignal)
  1319. {
  1320. (*mCommitSignal)(this, cbdata);
  1321. }
  1322. }
  1323. return res;
  1324. }
  1325. // private
  1326. BOOL LLTabContainer::setTab(S32 which)
  1327. {
  1328. static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
  1329. LLTabTuple* selected_tuple = getTab(which);
  1330. if (!selected_tuple)
  1331. {
  1332. return FALSE;
  1333. }
  1334. BOOL is_visible = FALSE;
  1335. if (selected_tuple->mButton->getEnabled())
  1336. {
  1337. setCurrentPanelIndex(which);
  1338. S32 i = 0;
  1339. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1340. {
  1341. LLTabTuple* tuple = *iter;
  1342. BOOL is_selected = ( tuple == selected_tuple );
  1343. tuple->mButton->setUseEllipses(mUseTabEllipses);
  1344. tuple->mButton->setHAlign(mFontHalign);
  1345. tuple->mTabPanel->setVisible( is_selected );
  1346. //  tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here.
  1347. tuple->mButton->setToggleState( is_selected );
  1348. // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs
  1349. tuple->mButton->setTabStop( is_selected );
  1350. if (is_selected)
  1351. {
  1352. // Make sure selected tab is within scroll region
  1353. if (mIsVertical)
  1354. {
  1355. S32 num_visible = getTabCount() - getMaxScrollPos();
  1356. if( i >= getScrollPos() && i <= getScrollPos() + num_visible)
  1357. {
  1358. setCurrentPanelIndex(which);
  1359. is_visible = TRUE;
  1360. }
  1361. else
  1362. {
  1363. is_visible = FALSE;
  1364. }
  1365. }
  1366. else if (getMaxScrollPos() > 0)
  1367. {
  1368. if( i < getScrollPos() )
  1369. {
  1370. setScrollPos(i);
  1371. }
  1372. else
  1373. {
  1374. S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
  1375. S32 running_tab_width = tuple->mButton->getRect().getWidth();
  1376. S32 j = i - 1;
  1377. S32 min_scroll_pos = i;
  1378. if (running_tab_width < available_width_with_arrows)
  1379. {
  1380. while (j >= 0)
  1381. {
  1382. LLTabTuple* other_tuple = getTab(j);
  1383. running_tab_width += other_tuple->mButton->getRect().getWidth();
  1384. if (running_tab_width > available_width_with_arrows)
  1385. {
  1386. break;
  1387. }
  1388. j--;
  1389. }
  1390. min_scroll_pos = j + 1;
  1391. }
  1392. setScrollPos(llclamp(getScrollPos(), min_scroll_pos, i));
  1393. setScrollPos(llmin(getScrollPos(), getMaxScrollPos()));
  1394. }
  1395. is_visible = TRUE;
  1396. }
  1397. else
  1398. {
  1399. is_visible = TRUE;
  1400. }
  1401. }
  1402. i++;
  1403. }
  1404. }
  1405. if (mIsVertical && getCurrentPanelIndex() >= 0)
  1406. {
  1407. LLTabTuple* tuple = getTab(getCurrentPanelIndex());
  1408. tuple->mTabPanel->setVisible( TRUE );
  1409. tuple->mButton->setToggleState( TRUE );
  1410. }
  1411. return is_visible;
  1412. }
  1413. BOOL LLTabContainer::selectTabByName(const std::string& name)
  1414. {
  1415. LLPanel* panel = getPanelByName(name);
  1416. if (!panel)
  1417. {
  1418. llwarns << "LLTabContainer::selectTabByName("
  1419. << name << ") failed" << llendl;
  1420. return FALSE;
  1421. }
  1422. BOOL result = selectTabPanel(panel);
  1423. return result;
  1424. }
  1425. BOOL LLTabContainer::getTabPanelFlashing(LLPanel *child)
  1426. {
  1427. LLTabTuple* tuple = getTabByPanel(child);
  1428. if( tuple )
  1429. {
  1430. return tuple->mButton->getFlashing();
  1431. }
  1432. return FALSE;
  1433. }
  1434. void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state )
  1435. {
  1436. LLTabTuple* tuple = getTabByPanel(child);
  1437. if( tuple )
  1438. {
  1439. tuple->mButton->setFlashing( state );
  1440. }
  1441. }
  1442. void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color)
  1443. {
  1444. LLTabTuple* tuple = getTabByPanel(child);
  1445. if( tuple )
  1446. {
  1447. tuple->mButton->setImageOverlay(image_name, LLFontGL::LEFT, color);
  1448. reshapeTuple(tuple);
  1449. }
  1450. }
  1451. void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const LLColor4& color)
  1452. {
  1453. LLTabTuple* tuple = getTabByPanel(child);
  1454. if( tuple )
  1455. {
  1456. tuple->mButton->setImageOverlay(image_id, LLFontGL::LEFT, color);
  1457. reshapeTuple(tuple);
  1458. }
  1459. }
  1460. void LLTabContainer::setTabImage(LLPanel* child, LLIconCtrl* icon)
  1461. {
  1462. LLTabTuple* tuple = getTabByPanel(child);
  1463. LLCustomButtonIconCtrl* button;
  1464. if(tuple)
  1465. {
  1466. button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton);
  1467. if(button)
  1468. {
  1469. button->setIcon(icon);
  1470. }
  1471. }
  1472. }
  1473. void LLTabContainer::reshapeTuple(LLTabTuple* tuple)
  1474. {
  1475. static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
  1476. if (!mIsVertical)
  1477. {
  1478. // remove current width from total tab strip width
  1479. mTotalTabWidth -= tuple->mButton->getRect().getWidth();
  1480. S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ?
  1481. tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : 0;
  1482. tuple->mPadding = image_overlay_width;
  1483. tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),
  1484. tuple->mButton->getRect().getHeight());
  1485. // add back in button width to total tab strip width
  1486. mTotalTabWidth += tuple->mButton->getRect().getWidth();
  1487. // tabs have changed size, might need to scroll to see current tab
  1488. updateMaxScrollPos();
  1489. }
  1490. }
  1491. void LLTabContainer::setTitle(const std::string& title)
  1492. {
  1493. if (mTitleBox)
  1494. {
  1495. mTitleBox->setText( title );
  1496. }
  1497. }
  1498. const std::string LLTabContainer::getPanelTitle(S32 index)
  1499. {
  1500. if (index >= 0 && index < (S32)mTabList.size())
  1501. {
  1502. LLButton* tab_button = mTabList[index]->mButton;
  1503. return tab_button->getLabelSelected();
  1504. }
  1505. return LLStringUtil::null;
  1506. }
  1507. void LLTabContainer::setTopBorderHeight(S32 height)
  1508. {
  1509. mTopBorderHeight = height;
  1510. }
  1511. S32 LLTabContainer::getTopBorderHeight() const
  1512. {
  1513. return mTopBorderHeight;
  1514. }
  1515. void LLTabContainer::setRightTabBtnOffset(S32 offset)
  1516. {
  1517. mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 );
  1518. mRightTabBtnOffset = offset;
  1519. updateMaxScrollPos();
  1520. }
  1521. void LLTabContainer::setPanelTitle(S32 index, const std::string& title)
  1522. {
  1523. static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
  1524. if (index >= 0 && index < getTabCount())
  1525. {
  1526. LLTabTuple* tuple = getTab(index);
  1527. LLButton* tab_button = tuple->mButton;
  1528. const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
  1529. mTotalTabWidth -= tab_button->getRect().getWidth();
  1530. tab_button->reshape(llclamp(fontp->getWidth(title) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight());
  1531. mTotalTabWidth += tab_button->getRect().getWidth();
  1532. tab_button->setLabelSelected(title);
  1533. tab_button->setLabelUnselected(title);
  1534. }
  1535. updateMaxScrollPos();
  1536. }
  1537. void LLTabContainer::onTabBtn( const LLSD& data, LLPanel* panel )
  1538. {
  1539. LLTabTuple* tuple = getTabByPanel(panel);
  1540. selectTabPanel( panel );
  1541. if (tuple)
  1542. {
  1543. tuple->mTabPanel->setFocus(TRUE);
  1544. }
  1545. }
  1546. void LLTabContainer::onNextBtn( const LLSD& data )
  1547. {
  1548. if (!mScrolled)
  1549. {
  1550. scrollNext();
  1551. }
  1552. mScrolled = FALSE;
  1553. }
  1554. void LLTabContainer::onNextBtnHeld( const LLSD& data )
  1555. {
  1556. if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
  1557. {
  1558. mScrollTimer.reset();
  1559. scrollNext();
  1560. mScrolled = TRUE;
  1561. }
  1562. }
  1563. void LLTabContainer::onPrevBtn( const LLSD& data )
  1564. {
  1565. if (!mScrolled)
  1566. {
  1567. scrollPrev();
  1568. }
  1569. mScrolled = FALSE;
  1570. }
  1571. void LLTabContainer::onJumpFirstBtn( const LLSD& data )
  1572. {
  1573. mScrollPos = 0;
  1574. }
  1575. void LLTabContainer::onJumpLastBtn( const LLSD& data )
  1576. {
  1577. mScrollPos = mMaxScrollPos;
  1578. }
  1579. void LLTabContainer::onPrevBtnHeld( const LLSD& data )
  1580. {
  1581. if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
  1582. {
  1583. mScrollTimer.reset();
  1584. scrollPrev();
  1585. mScrolled = TRUE;
  1586. }
  1587. }
  1588. // private
  1589. void LLTabContainer::initButtons()
  1590. {
  1591. // Hack:
  1592. if (getRect().getHeight() == 0 || mPrevArrowBtn)
  1593. {
  1594. return; // Don't have a rect yet or already got called
  1595. }
  1596. if (mIsVertical)
  1597. {
  1598. static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
  1599. // Left and right scroll arrows (for when there are too many tabs to show all at once).
  1600. S32 btn_top = getRect().getHeight();
  1601. S32 btn_top_lower = getRect().mBottom+tabcntrv_arrow_btn_size;
  1602. LLRect up_arrow_btn_rect;
  1603. up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size );
  1604. LLRect down_arrow_btn_rect;
  1605. down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size );
  1606. LLButton::Params prev_btn_params;
  1607. prev_btn_params.name(std::string("Up Arrow"));
  1608. prev_btn_params.rect(up_arrow_btn_rect);
  1609. prev_btn_params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
  1610. prev_btn_params.image_unselected.name("scrollbutton_up_out_blue.tga");
  1611. prev_btn_params.image_selected.name("scrollbutton_up_in_blue.tga");
  1612. prev_btn_params.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2));
  1613. mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(prev_btn_params);
  1614. LLButton::Params next_btn_params;
  1615. next_btn_params.name(std::string("Down Arrow"));
  1616. next_btn_params.rect(down_arrow_btn_rect);
  1617. next_btn_params.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_LEFT);
  1618. next_btn_params.image_unselected.name("scrollbutton_down_out_blue.tga");
  1619. next_btn_params.image_selected.name("scrollbutton_down_in_blue.tga");
  1620. next_btn_params.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2));
  1621. mNextArrowBtn = LLUICtrlFactory::create<LLButton>(next_btn_params);
  1622. }
  1623. else // Horizontal
  1624. {
  1625. static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
  1626. S32 arrow_fudge = 1; //  match new art better 
  1627. // Left and right scroll arrows (for when there are too many tabs to show all at once).
  1628. S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : tabcntr_arrow_btn_size + 1;
  1629. LLRect left_arrow_btn_rect;
  1630. left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+tabcntr_arrow_btn_size, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight );
  1631. LLRect jump_left_arrow_btn_rect;
  1632. jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, tabcntr_arrow_btn_size, mTabHeight );
  1633. S32 right_pad = tabcntr_arrow_btn_size + LLPANEL_BORDER_WIDTH + 1;
  1634. LLRect right_arrow_btn_rect;
  1635. right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - tabcntr_arrow_btn_size,
  1636. btn_top + arrow_fudge,
  1637. tabcntr_arrow_btn_size, mTabHeight );
  1638. LLRect jump_right_arrow_btn_rect;
  1639. jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad,
  1640.  btn_top + arrow_fudge,
  1641.  tabcntr_arrow_btn_size, mTabHeight );
  1642. LLButton::Params p;
  1643. p.name(std::string("Jump Left Arrow"));
  1644. p.image_unselected.name("jump_left_out.tga");
  1645. p.image_selected.name("jump_left_in.tga");
  1646. p.click_callback.function(boost::bind(&LLTabContainer::onJumpFirstBtn, this, _2));
  1647. p.rect(jump_left_arrow_btn_rect);
  1648. p.follows.flags(FOLLOWS_LEFT);
  1649. mJumpPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p);
  1650. p = LLButton::Params();
  1651. p.name(std::string("Left Arrow"));
  1652. p.rect(left_arrow_btn_rect);
  1653. p.follows.flags(FOLLOWS_LEFT);
  1654. p.image_unselected.name("scrollbutton_left_out_blue.tga");
  1655. p.image_selected.name("scrollbutton_left_in_blue.tga");
  1656. p.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2));
  1657. p.mouse_held_callback.function(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2));
  1658. mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p);
  1659. p = LLButton::Params();
  1660. p.name(std::string("Jump Right Arrow"));
  1661. p.rect(jump_right_arrow_btn_rect);
  1662. p.follows.flags(FOLLOWS_RIGHT);
  1663. p.image_unselected.name("jump_right_out.tga");
  1664. p.image_selected.name("jump_right_in.tga");
  1665. p.click_callback.function(boost::bind(&LLTabContainer::onJumpLastBtn, this, _2));
  1666. mJumpNextArrowBtn = LLUICtrlFactory::create<LLButton>(p);
  1667. p = LLButton::Params();
  1668. p.name(std::string("Right Arrow"));
  1669. p.rect(right_arrow_btn_rect);
  1670. p.follows.flags(FOLLOWS_RIGHT);
  1671. p.image_unselected.name("scrollbutton_right_out_blue.tga");
  1672. p.image_selected.name("scrollbutton_right_in_blue.tga");
  1673. p.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2));
  1674. p.mouse_held_callback.function(boost::bind(&LLTabContainer::onNextBtnHeld, this, _2));
  1675. mNextArrowBtn = LLUICtrlFactory::create<LLButton>(p);
  1676. if( getTabPosition() == TOP )
  1677. {
  1678. mNextArrowBtn->setFollowsTop();
  1679. mPrevArrowBtn->setFollowsTop();
  1680. mJumpPrevArrowBtn->setFollowsTop();
  1681. mJumpNextArrowBtn->setFollowsTop();
  1682. }
  1683. else
  1684. {
  1685. mNextArrowBtn->setFollowsBottom();
  1686. mPrevArrowBtn->setFollowsBottom();
  1687. mJumpPrevArrowBtn->setFollowsBottom();
  1688. mJumpNextArrowBtn->setFollowsBottom();
  1689. }
  1690. }
  1691. mPrevArrowBtn->setTabStop(FALSE);
  1692. addChild(mPrevArrowBtn);
  1693. mNextArrowBtn->setTabStop(FALSE);
  1694. addChild(mNextArrowBtn);
  1695. if (mJumpPrevArrowBtn)
  1696. {
  1697. mJumpPrevArrowBtn->setTabStop(FALSE);
  1698. addChild(mJumpPrevArrowBtn);
  1699. }
  1700. if (mJumpNextArrowBtn)
  1701. {
  1702. mJumpNextArrowBtn->setTabStop(FALSE);
  1703. addChild(mJumpNextArrowBtn);
  1704. }
  1705. // set default tab group to be panel contents
  1706. setDefaultTabGroup(1);
  1707. }
  1708. //this is a work around for the current LLPanel::initFromParams hack
  1709. //so that it doesn't overwrite the default tab group.
  1710. //will be removed when LLPanel is fixed soon.
  1711. void LLTabContainer::initFromParams(const LLPanel::Params& p)
  1712. {
  1713. LLPanel::initFromParams(p);
  1714. setDefaultTabGroup(1);
  1715. }
  1716. LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child)
  1717. {
  1718. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1719. {
  1720. LLTabTuple* tuple = *iter;
  1721. if( tuple->mTabPanel == child )
  1722. {
  1723. return tuple;
  1724. }
  1725. }
  1726. return NULL;
  1727. }
  1728. void LLTabContainer::insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point)
  1729. {
  1730. switch(insertion_point)
  1731. {
  1732. case START:
  1733. // insert the new tab in the front of the list
  1734. mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
  1735. break;
  1736. case LEFT_OF_CURRENT:
  1737. // insert the new tab before the current tab (but not before mLockedTabCount)
  1738. {
  1739. tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx);
  1740. mTabList.insert(current_iter, tuple);
  1741. }
  1742. break;
  1743. case RIGHT_OF_CURRENT:
  1744. // insert the new tab after the current tab (but not before mLockedTabCount)
  1745. {
  1746. tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1);
  1747. mTabList.insert(current_iter, tuple);
  1748. }
  1749. break;
  1750. case END:
  1751. default:
  1752. mTabList.push_back( tuple );
  1753. }
  1754. }
  1755. void LLTabContainer::updateMaxScrollPos()
  1756. {
  1757. static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
  1758. BOOL no_scroll = TRUE;
  1759. if (mIsVertical)
  1760. {
  1761. S32 tab_total_height = (BTN_HEIGHT + tabcntrv_pad) * getTabCount();
  1762. S32 available_height = getRect().getHeight() - getTopBorderHeight();
  1763. if( tab_total_height > available_height )
  1764. {
  1765. static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
  1766. S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad);
  1767. S32 additional_needed = tab_total_height - available_height_with_arrows;
  1768. setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) );
  1769. no_scroll = FALSE;
  1770. }
  1771. }
  1772. else
  1773. {
  1774. static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0);
  1775. static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
  1776. static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0);
  1777. S32 tab_space = 0;
  1778. S32 available_space = 0;
  1779. tab_space = mTotalTabWidth;
  1780. available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_tab_h_pad);
  1781. if( tab_space > available_space )
  1782. {
  1783. S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
  1784. // subtract off reserved portion on left
  1785. available_width_with_arrows -= tabcntr_tab_partial_width;
  1786. S32 running_tab_width = 0;
  1787. setMaxScrollPos(getTabCount());
  1788. for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it)
  1789. {
  1790. running_tab_width += (*tab_it)->mButton->getRect().getWidth();
  1791. if (running_tab_width > available_width_with_arrows)
  1792. {
  1793. break;
  1794. }
  1795. setMaxScrollPos(getMaxScrollPos()-1);
  1796. }
  1797. // in case last tab doesn't actually fit on screen, make it the last scrolling position
  1798. setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1));
  1799. no_scroll = FALSE;
  1800. }
  1801. }
  1802. if (no_scroll)
  1803. {
  1804. setMaxScrollPos(0);
  1805. setScrollPos(0);
  1806. }
  1807. if (getScrollPos() > getMaxScrollPos())
  1808. {
  1809. setScrollPos(getMaxScrollPos()); // maybe just enforce this via limits in setScrollPos instead?
  1810. }
  1811. }
  1812. void LLTabContainer::commitHoveredButton(S32 x, S32 y)
  1813. {
  1814. if (!getTabsHidden() && hasMouseCapture())
  1815. {
  1816. for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
  1817. {
  1818. LLTabTuple* tuple = *iter;
  1819. S32 local_x = x - tuple->mButton->getRect().mLeft;
  1820. S32 local_y = y - tuple->mButton->getRect().mBottom;
  1821. if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
  1822. {
  1823. tuple->mButton->onCommit();
  1824. }
  1825. }
  1826. }
  1827. }