lltabcontainer.cpp 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160
  1. /**
  2. * @file lltabcontainer.cpp
  3. * @brief LLTabContainer class
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, 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 "llbutton.h"
  35. #include "llcriticaldamp.h"
  36. #include "llrender.h"
  37. #include "llresizehandle.h"
  38. #include "llstl.h" // For DeletePointer()
  39. #include "lltextbox.h"
  40. #include "lluictrlfactory.h"
  41. constexpr F32 SCROLL_STEP_TIME = 0.4f;
  42. constexpr F32 SCROLL_DELAY_TIME = 0.5f;
  43. constexpr S32 TAB_PADDING = 15;
  44. constexpr S32 TABCNTR_TAB_MIN_WIDTH = 60;
  45. constexpr S32 TABCNTR_VERT_TAB_MIN_WIDTH = 100;
  46. constexpr S32 TABCNTR_TAB_MAX_WIDTH = 150;
  47. // When tabs are parially obscured, how much can you still see:
  48. constexpr S32 TABCNTR_TAB_PARTIAL_WIDTH = 12;
  49. constexpr S32 TABCNTR_TAB_HEIGHT = 16;
  50. constexpr S32 TABCNTR_ARROW_BTN_SIZE = 16;
  51. // How many pixels the tab buttons and tab panels overlap:
  52. constexpr S32 TABCNTR_BUTTON_PANEL_OVERLAP = 1;
  53. constexpr S32 TABCNTR_TAB_H_PAD = 4;
  54. constexpr S32 TABCNTR_TAB_BTN_MARGIN = LLPANEL_BORDER_WIDTH +
  55. 2 * (TABCNTR_ARROW_BTN_SIZE +
  56. TABCNTR_TAB_H_PAD);
  57. constexpr S32 TABCNTRV_ARROW_BTN_SIZE = 16;
  58. constexpr S32 TABCNTRV_PAD = 0;
  59. static const std::string LL_TAB_CONTAINER_COMMON_TAG = "tab_container";
  60. static LLRegisterWidget<LLTabContainer> r25(LL_TAB_CONTAINER_COMMON_TAG);
  61. LLTabContainer::LLTabContainer(const std::string& name, const LLRect& rect,
  62. TabPosition pos, bool bordered,bool vertical)
  63. : LLPanel(name, rect, bordered),
  64. mCurrentTabIdx(-1),
  65. mNextTabIdx(-1),
  66. mTabsHidden(false),
  67. mScrolled(false),
  68. mScrollPos(0),
  69. mScrollPosPixels(0),
  70. mMaxScrollPos(0),
  71. mCloseCallback(NULL),
  72. mCallbackUserdata(NULL),
  73. mTitleBox(NULL),
  74. mTopBorderHeight(LLPANEL_BORDER_WIDTH),
  75. mTabPosition(pos),
  76. mLockedTabCount(0),
  77. mMinTabWidth(TABCNTR_TAB_MIN_WIDTH),
  78. mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH),
  79. mPrevArrowBtn(NULL),
  80. mNextArrowBtn(NULL),
  81. mIsVertical(vertical),
  82. // Horizontal Specific
  83. mJumpPrevArrowBtn(NULL),
  84. mJumpNextArrowBtn(NULL),
  85. mRightTabBtnOffset(0),
  86. mTotalTabWidth(0)
  87. {
  88. // *HACK: to support default min width for legacy vertical tab containers
  89. if (mIsVertical)
  90. {
  91. mMinTabWidth = TABCNTR_VERT_TAB_MIN_WIDTH;
  92. }
  93. setMouseOpaque(false);
  94. initButtons();
  95. mDragAndDropDelayTimer.stop();
  96. }
  97. LLTabContainer::~LLTabContainer()
  98. {
  99. std::for_each(mTabList.begin(), mTabList.end(), DeletePointer());
  100. mTabList.clear();
  101. }
  102. //virtual
  103. void LLTabContainer::setValue(const LLSD& value)
  104. {
  105. selectTab((S32)value.asInteger());
  106. }
  107. //virtual
  108. void LLTabContainer::reshape(S32 width, S32 height, bool called_from_parent)
  109. {
  110. LLPanel::reshape(width, height, called_from_parent);
  111. updateMaxScrollPos();
  112. }
  113. //virtual
  114. LLView* LLTabContainer::getChildView(const char* name, bool recurse,
  115. bool create_if_missing) const
  116. {
  117. for (tuple_list_t::const_iterator itor = mTabList.begin(),
  118. end = mTabList.end();
  119. itor != end; ++itor)
  120. {
  121. LLPanel* panel = (*itor)->mTabPanel;
  122. if (strcmp(panel->getName().c_str(), name) == 0)
  123. {
  124. return panel;
  125. }
  126. }
  127. if (recurse)
  128. {
  129. for (tuple_list_t::const_iterator itor = mTabList.begin(),
  130. end = mTabList.end();
  131. itor != end; ++itor)
  132. {
  133. LLPanel* panel = (*itor)->mTabPanel;
  134. LLView* child = panel->getChildView(name, recurse, false);
  135. if (child)
  136. {
  137. return child;
  138. }
  139. }
  140. }
  141. return LLView::getChildView(name, recurse, create_if_missing);
  142. }
  143. //virtual
  144. void LLTabContainer::draw()
  145. {
  146. tuple_list_t::iterator begin = mTabList.begin();
  147. tuple_list_t::iterator end = mTabList.end();
  148. S32 target_pixel_scroll = 0;
  149. S32 cur_scroll_pos = getScrollPos();
  150. if (cur_scroll_pos > 0)
  151. {
  152. if (!mIsVertical)
  153. {
  154. S32 available_width_with_arrows = getRect().getWidth() -
  155. mRightTabBtnOffset -
  156. 2 * TABCNTR_TAB_BTN_MARGIN;
  157. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  158. {
  159. if (cur_scroll_pos == 0)
  160. {
  161. break;
  162. }
  163. target_pixel_scroll += (*iter)->mButton->getRect().getWidth();
  164. cur_scroll_pos--;
  165. }
  166. // Show part of the tab to the left of what is fully visible
  167. target_pixel_scroll -= TABCNTR_TAB_PARTIAL_WIDTH;
  168. // clamp so that rightmost tab never leaves right side of screen
  169. target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows,
  170. target_pixel_scroll);
  171. }
  172. else
  173. {
  174. S32 available_height_with_arrows = getRect().getHeight() -
  175. getTopBorderHeight() -
  176. TABCNTR_TAB_BTN_MARGIN;
  177. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  178. {
  179. if (cur_scroll_pos==0)
  180. {
  181. break;
  182. }
  183. target_pixel_scroll += (*iter)->mButton->getRect().getHeight();
  184. cur_scroll_pos--;
  185. }
  186. S32 total_tab_height = (gBtnHeight + TABCNTRV_PAD) * getTabCount() + TABCNTRV_PAD;
  187. // clamp so that the bottom tab never leaves bottom of panel
  188. target_pixel_scroll = llmin(total_tab_height - available_height_with_arrows,
  189. target_pixel_scroll);
  190. }
  191. }
  192. setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(),
  193. (F32)target_pixel_scroll,
  194. LLCriticalDamp::getInterpolant(0.08f)));
  195. bool has_scroll_arrows = mMaxScrollPos > 0 || mScrollPosPixels > 0;
  196. if (!mIsVertical)
  197. {
  198. mJumpPrevArrowBtn->setVisible(has_scroll_arrows);
  199. mJumpNextArrowBtn->setVisible(has_scroll_arrows);
  200. }
  201. mPrevArrowBtn->setVisible(has_scroll_arrows);
  202. mNextArrowBtn->setVisible(has_scroll_arrows);
  203. S32 left = 0, top = 0;
  204. if (mIsVertical)
  205. {
  206. top = getRect().getHeight() - getTopBorderHeight() -
  207. LLPANEL_BORDER_WIDTH - 1 -
  208. (has_scroll_arrows ? TABCNTRV_ARROW_BTN_SIZE : 0);
  209. top += getScrollPosPixels();
  210. }
  211. else
  212. {
  213. // Set the leftmost position of the tab buttons.
  214. left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? TABCNTR_ARROW_BTN_SIZE * 2
  215. : TABCNTR_TAB_H_PAD);
  216. left -= getScrollPosPixels();
  217. }
  218. // Hide all the buttons
  219. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  220. {
  221. LLTabTuple* tuple = *iter;
  222. if (tuple)
  223. {
  224. LLButton* tab_button = tuple->mButton;
  225. if (tab_button)
  226. {
  227. tab_button->setVisible(false);
  228. }
  229. }
  230. }
  231. LLPanel::draw();
  232. // If tabs are hidden, do not draw them and leave them in the invisible
  233. // state
  234. if (!getTabsHidden())
  235. {
  236. // Show all the buttons
  237. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  238. {
  239. LLTabTuple* tuple = *iter;
  240. if (tuple)
  241. {
  242. LLButton* tab_button = tuple->mButton;
  243. if (tab_button)
  244. {
  245. tab_button->setVisible(true);
  246. }
  247. }
  248. }
  249. // Draw some of the buttons...
  250. LLRect clip_rect = getLocalRect();
  251. if (has_scroll_arrows)
  252. {
  253. // ...but clip them.
  254. if (mIsVertical)
  255. {
  256. clip_rect.mBottom = mNextArrowBtn->getRect().mTop + 3*TABCNTRV_PAD;
  257. clip_rect.mTop = mPrevArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD;
  258. }
  259. else
  260. {
  261. clip_rect.mLeft = mPrevArrowBtn->getRect().mRight;
  262. clip_rect.mRight = mNextArrowBtn->getRect().mLeft;
  263. }
  264. }
  265. LLLocalClipRect clip(clip_rect);
  266. S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos();
  267. S32 idx = 0;
  268. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  269. {
  270. LLTabTuple* tuple = *iter;
  271. if (tuple)
  272. {
  273. LLButton* tab_button = tuple->mButton;
  274. if (tab_button)
  275. {
  276. tab_button->translate(left ? left - tab_button->getRect().mLeft
  277. : 0,
  278. top ? top - tab_button->getRect().mTop
  279. : 0);
  280. if (top)
  281. {
  282. top -= gBtnHeight + TABCNTRV_PAD;
  283. }
  284. if (left)
  285. {
  286. left += tab_button->getRect().getWidth();
  287. }
  288. if (!mIsVertical)
  289. {
  290. if (idx < getScrollPos())
  291. {
  292. if (tab_button->getFlashing())
  293. {
  294. mPrevArrowBtn->setFlashing(true);
  295. }
  296. }
  297. else if (max_scroll_visible < idx)
  298. {
  299. if (tab_button->getFlashing())
  300. {
  301. mNextArrowBtn->setFlashing(true);
  302. }
  303. }
  304. }
  305. LLUI::pushMatrix();
  306. {
  307. LLUI::translate((F32)tab_button->getRect().mLeft,
  308. (F32)tab_button->getRect().mBottom,
  309. 0.f);
  310. tab_button->draw();
  311. }
  312. LLUI::popMatrix();
  313. }
  314. }
  315. ++idx;
  316. }
  317. if (mIsVertical && has_scroll_arrows)
  318. {
  319. // Redraw the arrows so that they appears on top.
  320. gGL.pushUIMatrix();
  321. gGL.translateUI((F32)mPrevArrowBtn->getRect().mLeft,
  322. (F32)mPrevArrowBtn->getRect().mBottom, 0.f);
  323. mPrevArrowBtn->draw();
  324. gGL.popUIMatrix();
  325. gGL.pushUIMatrix();
  326. gGL.translateUI((F32)mNextArrowBtn->getRect().mLeft,
  327. (F32)mNextArrowBtn->getRect().mBottom, 0.f);
  328. mNextArrowBtn->draw();
  329. gGL.popUIMatrix();
  330. }
  331. }
  332. mPrevArrowBtn->setFlashing(false);
  333. mNextArrowBtn->setFlashing(false);
  334. }
  335. //virtual
  336. bool LLTabContainer::handleMouseDown(S32 x, S32 y, MASK mask)
  337. {
  338. bool handled = false;
  339. bool has_scroll_arrows = getMaxScrollPos() > 0;
  340. if (has_scroll_arrows)
  341. {
  342. if (mJumpPrevArrowBtn &&
  343. mJumpPrevArrowBtn->getRect().pointInRect(x, y))
  344. {
  345. S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
  346. S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
  347. handled = mJumpPrevArrowBtn->handleMouseDown(local_x, local_y, mask);
  348. }
  349. else if (mJumpNextArrowBtn &&
  350. mJumpNextArrowBtn->getRect().pointInRect(x, y))
  351. {
  352. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  353. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  354. handled = mJumpNextArrowBtn->handleMouseDown(local_x, local_y, mask);
  355. }
  356. else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
  357. {
  358. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  359. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  360. handled = mPrevArrowBtn->handleMouseDown(local_x, local_y, mask);
  361. }
  362. else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
  363. {
  364. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  365. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  366. handled = mNextArrowBtn->handleMouseDown(local_x, local_y, mask);
  367. }
  368. }
  369. if (!handled)
  370. {
  371. handled = LLPanel::handleMouseDown(x, y, mask);
  372. }
  373. S32 tab_count = getTabCount();
  374. if (tab_count > 0)
  375. {
  376. LLTabTuple* firsttuple = getTab(0);
  377. if (!firsttuple) return handled;
  378. LLButton* tab_button = firsttuple->mButton;
  379. if (!tab_button) return handled;
  380. LLRect tab_rect;
  381. if (mIsVertical)
  382. {
  383. tab_rect = LLRect(tab_button->getRect().mLeft,
  384. has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD
  385. : mPrevArrowBtn->getRect().mTop,
  386. tab_button->getRect().mRight,
  387. has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD
  388. : mNextArrowBtn->getRect().mBottom);
  389. }
  390. else
  391. {
  392. tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight
  393. : mJumpPrevArrowBtn->getRect().mLeft,
  394. tab_button->getRect().mTop,
  395. has_scroll_arrows ? mNextArrowBtn->getRect().mLeft
  396. : mJumpNextArrowBtn->getRect().mRight,
  397. tab_button->getRect().mBottom);
  398. }
  399. if (tab_rect.pointInRect(x, y))
  400. {
  401. S32 index = getCurrentPanelIndex();
  402. index = llclamp(index, 0, tab_count - 1);
  403. gFocusMgr.setMouseCapture(this);
  404. tab_button = getTab(index)->mButton;
  405. if (tab_button)
  406. {
  407. gFocusMgr.setKeyboardFocus(tab_button);
  408. }
  409. }
  410. }
  411. return handled;
  412. }
  413. //virtual
  414. bool LLTabContainer::handleHover(S32 x, S32 y, MASK mask)
  415. {
  416. bool handled = false;
  417. bool has_scroll_arrows = getMaxScrollPos() > 0;
  418. if (has_scroll_arrows)
  419. {
  420. if (mJumpPrevArrowBtn &&
  421. mJumpPrevArrowBtn->getRect().pointInRect(x, y))
  422. {
  423. S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
  424. S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
  425. handled = mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
  426. }
  427. else if (mJumpNextArrowBtn &&
  428. mJumpNextArrowBtn->getRect().pointInRect(x, y))
  429. {
  430. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  431. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  432. handled = mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
  433. }
  434. else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
  435. {
  436. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  437. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  438. handled = mPrevArrowBtn->handleHover(local_x, local_y, mask);
  439. }
  440. else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
  441. {
  442. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  443. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  444. handled = mNextArrowBtn->handleHover(local_x, local_y, mask);
  445. }
  446. }
  447. if (!handled)
  448. {
  449. handled = LLPanel::handleHover(x, y, mask);
  450. }
  451. commitHoveredButton(x, y);
  452. return handled;
  453. }
  454. //virtual
  455. bool LLTabContainer::handleMouseUp(S32 x, S32 y, MASK mask)
  456. {
  457. bool handled = false;
  458. bool has_scroll_arrows = getMaxScrollPos() > 0;
  459. if (has_scroll_arrows)
  460. {
  461. if (mJumpPrevArrowBtn &&
  462. 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->handleMouseUp(local_x, local_y, mask);
  467. }
  468. else if (mJumpNextArrowBtn &&
  469. mJumpNextArrowBtn->getRect().pointInRect(x, y))
  470. {
  471. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  472. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  473. handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask);
  474. }
  475. else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y))
  476. {
  477. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  478. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  479. handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask);
  480. }
  481. else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y))
  482. {
  483. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  484. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  485. handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask);
  486. }
  487. }
  488. if (!handled)
  489. {
  490. handled = LLPanel::handleMouseUp(x, y, mask);
  491. }
  492. commitHoveredButton(x, y);
  493. LLPanel* cur_panel = getCurrentPanel();
  494. if (hasMouseCapture())
  495. {
  496. #if 0 // This causes scroll list items to vanish when tab is selected. TODO:
  497. // find out why...
  498. // If nothing in the panel gets focus, make sure the new tab does
  499. // otherwise the last tab might keep focus
  500. if (cur_panel && !cur_panel->focusFirstItem(false))
  501. #else
  502. if (cur_panel)
  503. #endif
  504. {
  505. // Make sure new tab gets focus
  506. getTab(getCurrentPanelIndex())->mButton->setFocus(true);
  507. }
  508. gFocusMgr.setMouseCapture(NULL);
  509. }
  510. return handled;
  511. }
  512. //virtual
  513. bool LLTabContainer::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect)
  514. {
  515. bool handled = LLPanel::handleToolTip(x, y, msg, sticky_rect);
  516. if (!handled && getTabCount() > 0)
  517. {
  518. LLTabTuple* firsttuple = getTab(0);
  519. if (!firsttuple) return handled;
  520. LLButton* tab_button = firsttuple->mButton;
  521. if (!tab_button) return handled;
  522. bool has_scroll_arrows = getMaxScrollPos() > 0;
  523. LLRect clip;
  524. if (mIsVertical)
  525. {
  526. clip = LLRect(tab_button->getRect().mLeft,
  527. has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD
  528. : mPrevArrowBtn->getRect().mTop,
  529. tab_button->getRect().mRight,
  530. has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD
  531. : mNextArrowBtn->getRect().mBottom);
  532. }
  533. else
  534. {
  535. clip = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight
  536. : mJumpPrevArrowBtn->getRect().mLeft,
  537. tab_button->getRect().mTop,
  538. has_scroll_arrows ? mNextArrowBtn->getRect().mLeft
  539. : mJumpNextArrowBtn->getRect().mRight,
  540. tab_button->getRect().mBottom);
  541. }
  542. tuple_list_t::iterator begin = mTabList.begin();
  543. tuple_list_t::iterator end = mTabList.end();
  544. if (clip.pointInRect(x, y))
  545. {
  546. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  547. {
  548. LLTabTuple* tuple = *iter;
  549. if (!tuple) continue;
  550. tab_button = tuple->mButton;
  551. if (!tab_button) continue;
  552. tab_button->setVisible(true);
  553. S32 local_x = x - tab_button->getRect().mLeft;
  554. S32 local_y = y - tab_button->getRect().mBottom;
  555. handled = tab_button->handleToolTip(local_x, local_y, msg,
  556. sticky_rect);
  557. if (handled)
  558. {
  559. break;
  560. }
  561. }
  562. }
  563. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  564. {
  565. LLTabTuple* tuple = *iter;
  566. if (tuple)
  567. {
  568. tab_button = tuple->mButton;
  569. if (tab_button)
  570. {
  571. tab_button->setVisible(false);
  572. }
  573. }
  574. }
  575. }
  576. return handled;
  577. }
  578. //virtual
  579. bool LLTabContainer::handleKeyHere(KEY key, MASK mask)
  580. {
  581. bool handled = false;
  582. if (key == KEY_LEFT && mask == MASK_ALT)
  583. {
  584. selectPrevTab();
  585. handled = true;
  586. }
  587. else if (key == KEY_RIGHT && mask == MASK_ALT)
  588. {
  589. selectNextTab();
  590. handled = true;
  591. }
  592. if (handled)
  593. {
  594. if (getCurrentPanel())
  595. {
  596. getCurrentPanel()->setFocus(true);
  597. }
  598. }
  599. if (!gFocusMgr.childHasKeyboardFocus(getCurrentPanel()))
  600. {
  601. // if child has focus, but not the current panel, focus is on a button
  602. if (mIsVertical)
  603. {
  604. handled = true;
  605. switch (key)
  606. {
  607. case KEY_UP:
  608. selectPrevTab();
  609. break;
  610. case KEY_DOWN:
  611. selectNextTab();
  612. break;
  613. case KEY_LEFT:
  614. break;
  615. case KEY_RIGHT:
  616. if (getTabPosition() == LEFT && getCurrentPanel())
  617. {
  618. getCurrentPanel()->setFocus(true);
  619. }
  620. break;
  621. default:
  622. handled = false;
  623. }
  624. }
  625. else
  626. {
  627. handled = true;
  628. switch (key)
  629. {
  630. case KEY_UP:
  631. if (getTabPosition() == BOTTOM && getCurrentPanel())
  632. {
  633. getCurrentPanel()->setFocus(true);
  634. }
  635. break;
  636. case KEY_DOWN:
  637. if (getTabPosition() == TOP && getCurrentPanel())
  638. {
  639. getCurrentPanel()->setFocus(true);
  640. }
  641. break;
  642. case KEY_LEFT:
  643. selectPrevTab();
  644. break;
  645. case KEY_RIGHT:
  646. selectNextTab();
  647. break;
  648. default:
  649. handled = false;
  650. }
  651. }
  652. }
  653. return handled;
  654. }
  655. //virtual
  656. const std::string& LLTabContainer::getTag() const
  657. {
  658. return LL_TAB_CONTAINER_COMMON_TAG;
  659. }
  660. //virtual
  661. LLXMLNodePtr LLTabContainer::getXML(bool save_children) const
  662. {
  663. LLXMLNodePtr nodep = LLPanel::getXML();
  664. nodep->setName(LL_TAB_CONTAINER_COMMON_TAG);
  665. const std::string pos = getTabPosition() == TOP ? "top" : "bottom";
  666. nodep->createChild("tab_position", true)->setStringValue(pos);
  667. return nodep;
  668. }
  669. //virtual
  670. bool LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
  671. EDragAndDropType type, void* cargo_data,
  672. EAcceptance* accept,
  673. std::string& tooltip)
  674. {
  675. bool has_scroll_arrows = getMaxScrollPos() > 0;
  676. if (mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME)
  677. {
  678. if (has_scroll_arrows)
  679. {
  680. if (mJumpPrevArrowBtn &&
  681. mJumpPrevArrowBtn->getRect().pointInRect(x, y))
  682. {
  683. S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft;
  684. S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom;
  685. mJumpPrevArrowBtn->handleHover(local_x, local_y, mask);
  686. }
  687. if (mJumpNextArrowBtn &&
  688. mJumpNextArrowBtn->getRect().pointInRect(x, y))
  689. {
  690. S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft;
  691. S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom;
  692. mJumpNextArrowBtn->handleHover(local_x, local_y, mask);
  693. }
  694. if (mPrevArrowBtn->getRect().pointInRect(x, y))
  695. {
  696. S32 local_x = x - mPrevArrowBtn->getRect().mLeft;
  697. S32 local_y = y - mPrevArrowBtn->getRect().mBottom;
  698. mPrevArrowBtn->handleHover(local_x, local_y, mask);
  699. }
  700. else if (mNextArrowBtn->getRect().pointInRect(x, y))
  701. {
  702. S32 local_x = x - mNextArrowBtn->getRect().mLeft;
  703. S32 local_y = y - mNextArrowBtn->getRect().mBottom;
  704. mNextArrowBtn->handleHover(local_x, local_y, mask);
  705. }
  706. }
  707. for (tuple_list_t::iterator iter = mTabList.begin(),
  708. end = mTabList.end();
  709. iter != end; ++iter)
  710. {
  711. LLTabTuple* tuple = *iter;
  712. if (!tuple) continue;
  713. LLButton* tab_button = tuple->mButton;
  714. if (!tab_button) continue;
  715. tab_button->setVisible(true);
  716. S32 local_x = x - tab_button->getRect().mLeft;
  717. S32 local_y = y - tab_button->getRect().mBottom;
  718. if (tab_button->pointInView(local_x, local_y) &&
  719. tab_button->getEnabled() && !tuple->mTabPanel->getVisible())
  720. {
  721. tab_button->onCommit();
  722. mDragAndDropDelayTimer.stop();
  723. }
  724. }
  725. }
  726. return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data,
  727. accept, tooltip);
  728. }
  729. void LLTabContainer::addTabPanel(LLPanel* child, const std::string& label,
  730. bool select,
  731. void (*on_tab_clicked)(void*, bool),
  732. void* userdata,
  733. S32 indent, bool placeholder,
  734. eInsertionPoint insertion_point)
  735. {
  736. if (child->getParent() == this)
  737. {
  738. // Already a child of mine
  739. return;
  740. }
  741. const LLFontGL* font = mIsVertical ? LLFontGL::getFontSansSerif()
  742. : LLFontGL::getFontSansSerifSmall();
  743. // Store the original label for possible xml export.
  744. child->setLabel(label);
  745. std::string trimmed_label = label;
  746. LLStringUtil::trim(trimmed_label);
  747. S32 button_width = mMinTabWidth;
  748. if (!mIsVertical)
  749. {
  750. button_width = llclamp(font->getWidth(trimmed_label) + TAB_PADDING,
  751. mMinTabWidth, mMaxTabWidth);
  752. }
  753. // Tab panel
  754. S32 tab_panel_top;
  755. S32 tab_panel_bottom;
  756. if (getTabPosition() == LLTabContainer::TOP)
  757. {
  758. S32 tab_height = mIsVertical ? gBtnHeight : TABCNTR_TAB_HEIGHT;
  759. tab_panel_top = getRect().getHeight() - getTopBorderHeight() -
  760. (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP);
  761. tab_panel_bottom = LLPANEL_BORDER_WIDTH;
  762. }
  763. else
  764. {
  765. tab_panel_top = getRect().getHeight() - getTopBorderHeight();
  766. // Run to the edge, covering up the border
  767. tab_panel_bottom = TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP;
  768. }
  769. LLRect tab_panel_rect;
  770. if (mIsVertical)
  771. {
  772. tab_panel_rect = LLRect(mMinTabWidth + LLPANEL_BORDER_WIDTH * 2 + TABCNTRV_PAD,
  773. getRect().getHeight() - LLPANEL_BORDER_WIDTH,
  774. getRect().getWidth() - LLPANEL_BORDER_WIDTH,
  775. LLPANEL_BORDER_WIDTH);
  776. }
  777. else
  778. {
  779. tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH, tab_panel_top,
  780. getRect().getWidth() - LLPANEL_BORDER_WIDTH,
  781. tab_panel_bottom);
  782. }
  783. child->setFollowsAll();
  784. child->translate(tab_panel_rect.mLeft - child->getRect().mLeft,
  785. tab_panel_rect.mBottom - child->getRect().mBottom);
  786. child->reshape(tab_panel_rect.getWidth(), tab_panel_rect.getHeight());
  787. // Add this child later
  788. child->setVisible(false); // Will be made visible when selected
  789. mTotalTabWidth += button_width;
  790. // Tab button
  791. // Note: btn_rect.mLeft is just a dummy. Will be updated in draw().
  792. LLRect btn_rect;
  793. std::string tab_img;
  794. std::string tab_selected_img;
  795. // To make new tab art look better, nudge buttons up 1 pixel
  796. S32 tab_fudge = 1;
  797. if (mIsVertical)
  798. {
  799. btn_rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
  800. getRect().getHeight() -
  801. getTopBorderHeight() -
  802. LLPANEL_BORDER_WIDTH - 1 -
  803. (gBtnHeight + TABCNTRV_PAD) * getTabCount(),
  804. mMinTabWidth, gBtnHeight);
  805. }
  806. else if (getTabPosition() == LLTabContainer::TOP)
  807. {
  808. btn_rect.setLeftTopAndSize(0,
  809. getRect().getHeight() -
  810. getTopBorderHeight() + tab_fudge,
  811. button_width, TABCNTR_TAB_HEIGHT);
  812. tab_img = "tab_top_blue.tga";
  813. tab_selected_img = "tab_top_selected_blue.tga";
  814. }
  815. else
  816. {
  817. btn_rect.setOriginAndSize(0, tab_fudge, button_width,
  818. TABCNTR_TAB_HEIGHT);
  819. tab_img = "tab_bottom_blue.tga";
  820. tab_selected_img = "tab_bottom_selected_blue.tga";
  821. }
  822. LLTextBox* textbox = NULL;
  823. LLButton* btn = NULL;
  824. if (placeholder)
  825. {
  826. btn_rect.translate(0, -gButtonVPad - 2);
  827. textbox = new LLTextBox(trimmed_label, btn_rect, trimmed_label, font);
  828. btn = new LLButton(LLStringUtil::null, LLRect(0, 0, 0, 0));
  829. }
  830. else
  831. {
  832. if (mIsVertical)
  833. {
  834. btn = new LLButton("vert tab button", btn_rect, LLStringUtil::null,
  835. LLStringUtil::null, NULL,
  836. &LLTabContainer::onTabBtn, NULL,
  837. font, trimmed_label, trimmed_label);
  838. btn->setImages("tab_left.tga", "tab_left_selected.tga");
  839. btn->setScaleImage(true);
  840. btn->setHAlign(LLFontGL::LEFT);
  841. btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
  842. btn->setTabStop(false);
  843. if (indent)
  844. {
  845. btn->setLeftHPad(indent);
  846. }
  847. }
  848. else
  849. {
  850. std::string tooltip = trimmed_label;
  851. tooltip += "\nAlt-Left arrow for previous tab";
  852. tooltip += "\nAlt-Right arrow for next tab";
  853. btn = new LLButton(child->getName() + " tab", btn_rect,
  854. LLStringUtil::null, LLStringUtil::null, NULL,
  855. &LLTabContainer::onTabBtn,
  856. NULL, // Set userdata below
  857. font, trimmed_label, trimmed_label);
  858. btn->setVisible(false);
  859. btn->setToolTip(tooltip);
  860. btn->setScaleImage(true);
  861. btn->setImages(tab_img, tab_selected_img);
  862. // Try to squeeze in a bit more text
  863. btn->setLeftHPad(4);
  864. btn->setRightHPad(2);
  865. btn->setHAlign(LLFontGL::LEFT);
  866. btn->setTabStop(false);
  867. if (indent)
  868. {
  869. btn->setLeftHPad(indent);
  870. }
  871. if (getTabPosition() == TOP)
  872. {
  873. btn->setFollowsTop();
  874. }
  875. else
  876. {
  877. btn->setFollowsBottom();
  878. }
  879. }
  880. }
  881. LLTabTuple* tuple = new LLTabTuple(this, child, btn, on_tab_clicked,
  882. userdata, textbox);
  883. insertTuple(tuple, insertion_point);
  884. if (textbox)
  885. {
  886. textbox->setSaveToXML(false);
  887. addChild(textbox, 0);
  888. }
  889. if (btn)
  890. {
  891. btn->setSaveToXML(false);
  892. btn->setCallbackUserData(tuple);
  893. addChild(btn, 0);
  894. }
  895. if (child)
  896. {
  897. addChild(child, 1);
  898. }
  899. if (select)
  900. {
  901. selectLastTab();
  902. }
  903. updateMaxScrollPos();
  904. }
  905. void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label)
  906. {
  907. addTabPanel(child, label, false, NULL, NULL, 0, true);
  908. }
  909. void LLTabContainer::removeTabPanel(LLPanel* child)
  910. {
  911. tuple_list_t::iterator begin = mTabList.begin();
  912. tuple_list_t::iterator end = mTabList.end();
  913. if (mIsVertical)
  914. {
  915. // Fix-up button sizes
  916. S32 tab_count = 0;
  917. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  918. {
  919. LLTabTuple* tuple = *iter;
  920. LLRect rect;
  921. rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
  922. getRect().getHeight() -
  923. LLPANEL_BORDER_WIDTH - 1 -
  924. (gBtnHeight + TABCNTRV_PAD) * tab_count,
  925. mMinTabWidth, gBtnHeight);
  926. if (tuple->mPlaceholderText)
  927. {
  928. tuple->mPlaceholderText->setRect(rect);
  929. }
  930. else if (tuple->mButton)
  931. {
  932. tuple->mButton->setRect(rect);
  933. }
  934. ++tab_count;
  935. }
  936. }
  937. else
  938. {
  939. // Adjust the total tab width.
  940. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  941. {
  942. LLTabTuple* tuple = *iter;
  943. if (tuple->mTabPanel == child && tuple->mButton)
  944. {
  945. mTotalTabWidth -= tuple->mButton->getRect().getWidth();
  946. break;
  947. }
  948. }
  949. }
  950. bool has_focus = gFocusMgr.childHasKeyboardFocus(this);
  951. // If the tab being deleted is the selected one, select a different tab.
  952. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  953. {
  954. LLTabTuple* tuple = *iter;
  955. if (tuple->mTabPanel == child)
  956. {
  957. if (tuple->mButton)
  958. {
  959. removeChild(tuple->mButton);
  960. delete tuple->mButton;
  961. }
  962. removeChild(tuple->mTabPanel);
  963. #if 0
  964. delete tuple->mTabPanel;
  965. #endif
  966. mTabList.erase(iter);
  967. delete tuple;
  968. break;
  969. }
  970. }
  971. // Make sure we do not have more locked tabs than we have tabs
  972. mLockedTabCount = llmin(getTabCount(), mLockedTabCount);
  973. if (mCurrentTabIdx >= (S32)mTabList.size())
  974. {
  975. mCurrentTabIdx = mTabList.size() - 1;
  976. }
  977. selectTab(mCurrentTabIdx);
  978. if (has_focus)
  979. {
  980. LLPanel* panelp = getPanelByIndex(mCurrentTabIdx);
  981. if (panelp)
  982. {
  983. panelp->setFocus(true);
  984. }
  985. }
  986. updateMaxScrollPos();
  987. }
  988. void LLTabContainer::lockTabs(S32 num_tabs)
  989. {
  990. // Count current tabs or use supplied value and ensure no new tabs get
  991. // inserted between them
  992. mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs)
  993. : getTabCount();
  994. }
  995. void LLTabContainer::unlockTabs()
  996. {
  997. mLockedTabCount = 0;
  998. }
  999. void LLTabContainer::enableTabButton(S32 which, bool enable)
  1000. {
  1001. if (which >= 0 && which < (S32)mTabList.size())
  1002. {
  1003. mTabList[which]->mButton->setEnabled(enable);
  1004. }
  1005. }
  1006. void LLTabContainer::deleteAllTabs()
  1007. {
  1008. tuple_list_t::iterator begin = mTabList.begin();
  1009. tuple_list_t::iterator end = mTabList.end();
  1010. // Remove all the tab buttons and delete them. Also, unlink all the child
  1011. // panels.
  1012. for (tuple_list_t::iterator iter = begin; iter != end; ++iter)
  1013. {
  1014. LLTabTuple* tuple = *iter;
  1015. if (tuple->mButton)
  1016. {
  1017. removeChild(tuple->mButton);
  1018. delete tuple->mButton;
  1019. }
  1020. removeChild(tuple->mTabPanel);
  1021. #if 0
  1022. delete tuple->mTabPanel;
  1023. #endif
  1024. }
  1025. // Actually delete the tuples themselves
  1026. std::for_each(begin, end, DeletePointer());
  1027. mTabList.clear();
  1028. // And there is not a current tab any more
  1029. mCurrentTabIdx = -1;
  1030. }
  1031. LLPanel* LLTabContainer::getCurrentPanel()
  1032. {
  1033. if (mCurrentTabIdx >= 0 && mCurrentTabIdx < (S32) mTabList.size())
  1034. {
  1035. return mTabList[mCurrentTabIdx]->mTabPanel;
  1036. }
  1037. return NULL;
  1038. }
  1039. S32 LLTabContainer::getCurrentPanelIndex()
  1040. {
  1041. return mCurrentTabIdx;
  1042. }
  1043. S32 LLTabContainer::getTabCount()
  1044. {
  1045. return mTabList.size();
  1046. }
  1047. LLPanel* LLTabContainer::getPanelByIndex(S32 index)
  1048. {
  1049. if (index >= 0 && index < (S32)mTabList.size())
  1050. {
  1051. return mTabList[index]->mTabPanel;
  1052. }
  1053. return NULL;
  1054. }
  1055. S32 LLTabContainer::getIndexForPanel(LLPanel* panel)
  1056. {
  1057. for (S32 index = 0, count = mTabList.size(); index < count; ++index)
  1058. {
  1059. if (mTabList[index]->mTabPanel == panel)
  1060. {
  1061. return index;
  1062. }
  1063. }
  1064. return -1;
  1065. }
  1066. S32 LLTabContainer::getPanelIndexByTitle(const std::string& title)
  1067. {
  1068. for (S32 index = 0, count = mTabList.size(); index < count; ++index)
  1069. {
  1070. if (title == mTabList[index]->mButton->getLabelSelected())
  1071. {
  1072. return index;
  1073. }
  1074. }
  1075. return -1;
  1076. }
  1077. LLPanel* LLTabContainer::getPanelByName(const std::string& name)
  1078. {
  1079. for (S32 index = 0, count = mTabList.size(); index < count; ++index)
  1080. {
  1081. LLPanel* panel = mTabList[index]->mTabPanel;
  1082. if (name == panel->getName())
  1083. {
  1084. return panel;
  1085. }
  1086. }
  1087. return NULL;
  1088. }
  1089. // Change the name of the button for the current tab.
  1090. void LLTabContainer::setCurrentTabName(const std::string& name)
  1091. {
  1092. // Might not have a tab selected
  1093. if (mCurrentTabIdx < 0) return;
  1094. mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name);
  1095. mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name);
  1096. }
  1097. void LLTabContainer::selectFirstTab()
  1098. {
  1099. selectTab(0);
  1100. }
  1101. void LLTabContainer::selectLastTab()
  1102. {
  1103. selectTab(mTabList.size() - 1);
  1104. }
  1105. void LLTabContainer::selectNextTab()
  1106. {
  1107. bool tab_has_focus = false;
  1108. if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
  1109. {
  1110. tab_has_focus = true;
  1111. }
  1112. S32 idx = mCurrentTabIdx+1;
  1113. if (idx >= (S32)mTabList.size())
  1114. {
  1115. idx = 0;
  1116. }
  1117. while (!selectTab(idx) && idx != mCurrentTabIdx)
  1118. {
  1119. idx = (idx + 1) % (S32)mTabList.size();
  1120. }
  1121. if (tab_has_focus)
  1122. {
  1123. mTabList[idx]->mButton->setFocus(true);
  1124. }
  1125. }
  1126. void LLTabContainer::selectPrevTab()
  1127. {
  1128. bool tab_has_focus = false;
  1129. if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus())
  1130. {
  1131. tab_has_focus = true;
  1132. }
  1133. S32 idx = mCurrentTabIdx - 1;
  1134. if (idx < 0)
  1135. {
  1136. idx = mTabList.size() - 1;
  1137. }
  1138. while (!selectTab(idx) && idx != mCurrentTabIdx)
  1139. {
  1140. if (--idx < 0)
  1141. {
  1142. idx = mTabList.size() - 1;
  1143. }
  1144. }
  1145. if (tab_has_focus)
  1146. {
  1147. mTabList[idx]->mButton->setFocus(true);
  1148. }
  1149. }
  1150. bool LLTabContainer::selectTabPanel(LLPanel* child)
  1151. {
  1152. S32 idx = 0;
  1153. for (tuple_list_t::iterator iter = mTabList.begin(),
  1154. end = mTabList.end();
  1155. iter != end; ++iter)
  1156. {
  1157. LLTabTuple* tuple = *iter;
  1158. if (tuple->mTabPanel == child)
  1159. {
  1160. return selectTab(idx);
  1161. }
  1162. ++idx;
  1163. }
  1164. return false;
  1165. }
  1166. bool LLTabContainer::selectTab(S32 which)
  1167. {
  1168. if (which >= getTabCount() || which < 0)
  1169. {
  1170. return false;
  1171. }
  1172. #if 0
  1173. if (gFocusMgr.childHasKeyboardFocus(this))
  1174. {
  1175. gFocusMgr.setKeyboardFocus(NULL);
  1176. }
  1177. #endif
  1178. LLTabTuple* selected_tuple = getTab(which);
  1179. if (!selected_tuple)
  1180. {
  1181. return false;
  1182. }
  1183. if (!selected_tuple->mPrecommitChangeCallback)
  1184. {
  1185. return setTab(which);
  1186. }
  1187. mNextTabIdx = which;
  1188. selected_tuple->mPrecommitChangeCallback(selected_tuple->mUserData, false);
  1189. return true;
  1190. }
  1191. bool LLTabContainer::setTab(S32 which)
  1192. {
  1193. if (which == -1)
  1194. {
  1195. if (mNextTabIdx == -1)
  1196. {
  1197. return false;
  1198. }
  1199. which = mNextTabIdx;
  1200. mNextTabIdx = -1;
  1201. }
  1202. LLTabTuple* selected_tuple = getTab(which);
  1203. if (!selected_tuple)
  1204. {
  1205. return false;
  1206. }
  1207. bool is_visible = false;
  1208. if (selected_tuple->mButton->getEnabled())
  1209. {
  1210. setCurrentPanelIndex(which);
  1211. S32 i = 0;
  1212. for (tuple_list_t::iterator iter = mTabList.begin(),
  1213. end = mTabList.end();
  1214. iter != end; ++iter)
  1215. {
  1216. LLTabTuple* tuple = *iter;
  1217. bool is_selected = tuple == selected_tuple;
  1218. tuple->mTabPanel->setVisible(is_selected);
  1219. #if 0 // not clear that we want to do this here.
  1220. tuple->mTabPanel->setFocus(is_selected);
  1221. #endif
  1222. tuple->mButton->setToggleState(is_selected);
  1223. // RN: this limits tab-stops to active button only, which would
  1224. // require arrow keys to switch tabs
  1225. tuple->mButton->setTabStop(is_selected);
  1226. if (is_selected && (mIsVertical || getMaxScrollPos() > 0))
  1227. {
  1228. // Make sure selected tab is within scroll region
  1229. if (mIsVertical)
  1230. {
  1231. S32 num_visible = getTabCount() - getMaxScrollPos();
  1232. if (i >= getScrollPos() &&
  1233. i <= getScrollPos() + num_visible)
  1234. {
  1235. setCurrentPanelIndex(which);
  1236. is_visible = true;
  1237. }
  1238. else
  1239. {
  1240. is_visible = false;
  1241. }
  1242. }
  1243. else if (tuple->mButton)
  1244. {
  1245. if (i < getScrollPos())
  1246. {
  1247. setScrollPos(i);
  1248. }
  1249. else
  1250. {
  1251. S32 available_width_with_arrows = getRect().getWidth() -
  1252. mRightTabBtnOffset -
  1253. 2 * (LLPANEL_BORDER_WIDTH +
  1254. TABCNTR_ARROW_BTN_SIZE +
  1255. TABCNTR_ARROW_BTN_SIZE + 1);
  1256. S32 running_tab_width = tuple->mButton->getRect().getWidth();
  1257. S32 j = i - 1;
  1258. S32 min_scroll_pos = i;
  1259. if (running_tab_width < available_width_with_arrows)
  1260. {
  1261. while (j >= 0)
  1262. {
  1263. LLTabTuple* other_tuple = getTab(j);
  1264. if (other_tuple && other_tuple->mButton)
  1265. {
  1266. running_tab_width += other_tuple->mButton->getRect().getWidth();
  1267. }
  1268. if (running_tab_width > available_width_with_arrows)
  1269. {
  1270. break;
  1271. }
  1272. --j;
  1273. }
  1274. min_scroll_pos = j + 1;
  1275. }
  1276. setScrollPos(llclamp(getScrollPos(),
  1277. min_scroll_pos, i));
  1278. setScrollPos(llmin(getScrollPos(), getMaxScrollPos()));
  1279. }
  1280. is_visible = true;
  1281. }
  1282. }
  1283. ++i;
  1284. }
  1285. if (selected_tuple->mOnChangeCallback)
  1286. {
  1287. selected_tuple->mOnChangeCallback(selected_tuple->mUserData,
  1288. false);
  1289. }
  1290. }
  1291. if (mIsVertical && getCurrentPanelIndex() >= 0)
  1292. {
  1293. LLTabTuple* tuple = getTab(getCurrentPanelIndex());
  1294. if (tuple && tuple->mTabPanel && tuple->mButton)
  1295. {
  1296. tuple->mTabPanel->setVisible(true);
  1297. tuple->mButton->setToggleState(true);
  1298. }
  1299. }
  1300. return is_visible;
  1301. }
  1302. bool LLTabContainer::selectTabByName(const std::string& name)
  1303. {
  1304. LLPanel* panel = getPanelByName(name);
  1305. if (!panel)
  1306. {
  1307. llwarns << "Cannot find a tab named: " << name << llendl;
  1308. return false;
  1309. }
  1310. return selectTabPanel(panel);
  1311. }
  1312. bool LLTabContainer::getTabPanelFlashing(LLPanel *child)
  1313. {
  1314. LLTabTuple* tuple = getTabByPanel(child);
  1315. if (tuple && tuple->mButton)
  1316. {
  1317. return tuple->mButton->getFlashing();
  1318. }
  1319. return false;
  1320. }
  1321. void LLTabContainer::setTabPanelFlashing(LLPanel* child, bool state)
  1322. {
  1323. LLTabTuple* tuple = getTabByPanel(child);
  1324. if (tuple && tuple->mButton)
  1325. {
  1326. tuple->mButton->setFlashing(state);
  1327. }
  1328. }
  1329. void LLTabContainer::setTabButtonTooltip(LLPanel* child,
  1330. const std::string& tooltip)
  1331. {
  1332. for (tuple_list_t::iterator iter = mTabList.begin(),
  1333. end = mTabList.end();
  1334. iter != end; ++iter)
  1335. {
  1336. LLTabTuple* tuple = *iter;
  1337. if (tuple->mTabPanel == child)
  1338. {
  1339. if (!mIsVertical && tooltip.empty())
  1340. {
  1341. std::string deflt = tuple->mButton->getLabelUnselected();
  1342. deflt += "\nAlt-Left arrow for previous tab";
  1343. deflt += "\nAlt-Right arrow for next tab";
  1344. tuple->mButton->setToolTip(deflt);
  1345. return;
  1346. }
  1347. tuple->mButton->setToolTip(tooltip);
  1348. return;
  1349. }
  1350. }
  1351. }
  1352. void LLTabContainer::setTabImage(LLPanel* child, std::string image_name,
  1353. const LLColor4& color)
  1354. {
  1355. LLTabTuple* tuple = getTabByPanel(child);
  1356. if (!tuple) return;
  1357. LLButton* button = tuple->mButton;
  1358. if (!button) return;
  1359. button->setImageOverlay(image_name, LLFontGL::RIGHT, color);
  1360. if (mIsVertical)
  1361. {
  1362. return;
  1363. }
  1364. // Remove current width from total tab strip width
  1365. mTotalTabWidth -= button->getRect().getWidth();
  1366. S32 image_overlay_width = 0;
  1367. if (button->getImageOverlay().notNull())
  1368. {
  1369. image_overlay_width = button->getImageOverlay()->getImage()->getWidth(0);
  1370. }
  1371. tuple->mPadding = image_overlay_width;
  1372. button->setRightHPad(6);
  1373. static const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
  1374. button->reshape(llclamp(fontp->getWidth(button->getLabelSelected()) +
  1375. TAB_PADDING + tuple->mPadding,
  1376. mMinTabWidth, mMaxTabWidth),
  1377. button->getRect().getHeight());
  1378. // Add back in button width to total tab strip width
  1379. mTotalTabWidth += button->getRect().getWidth();
  1380. // Tabs have changed size, might need to scroll to see current tab
  1381. updateMaxScrollPos();
  1382. }
  1383. void LLTabContainer::setTitle(const std::string& title)
  1384. {
  1385. if (mTitleBox)
  1386. {
  1387. mTitleBox->setText(title);
  1388. }
  1389. }
  1390. const std::string LLTabContainer::getPanelTitle(S32 index)
  1391. {
  1392. if (index >= 0 && index < (S32)mTabList.size())
  1393. {
  1394. LLButton* tab_button = mTabList[index]->mButton;
  1395. return tab_button->getLabelSelected();
  1396. }
  1397. return LLStringUtil::null;
  1398. }
  1399. void LLTabContainer::setTopBorderHeight(S32 height)
  1400. {
  1401. mTopBorderHeight = height;
  1402. }
  1403. S32 LLTabContainer::getTopBorderHeight() const
  1404. {
  1405. return mTopBorderHeight;
  1406. }
  1407. void LLTabContainer::setTabChangeCallback(LLPanel* tab,
  1408. void (*on_tab_clicked)(void*, bool))
  1409. {
  1410. LLTabTuple* tuplep = getTabByPanel(tab);
  1411. if (tuplep)
  1412. {
  1413. tuplep->mOnChangeCallback = on_tab_clicked;
  1414. }
  1415. }
  1416. void LLTabContainer::setTabPrecommitChangeCallback(LLPanel* tab,
  1417. void (*on_precommit)(void*, bool))
  1418. {
  1419. LLTabTuple* tuplep = getTabByPanel(tab);
  1420. if (tuplep)
  1421. {
  1422. tuplep->mPrecommitChangeCallback = on_precommit;
  1423. }
  1424. }
  1425. void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata)
  1426. {
  1427. LLTabTuple* tuplep = getTabByPanel(tab);
  1428. if (tuplep)
  1429. {
  1430. tuplep->mUserData = userdata;
  1431. }
  1432. }
  1433. void LLTabContainer::setRightTabBtnOffset(S32 offset)
  1434. {
  1435. mNextArrowBtn->translate(-offset - mRightTabBtnOffset, 0);
  1436. mRightTabBtnOffset = offset;
  1437. updateMaxScrollPos();
  1438. }
  1439. void LLTabContainer::setPanelTitle(S32 index, const std::string& title)
  1440. {
  1441. static const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
  1442. if (index >= 0 && index < getTabCount())
  1443. {
  1444. LLTabTuple* tuple = getTab(index);
  1445. if (tuple)
  1446. {
  1447. LLButton* tab_button = tuple->mButton;
  1448. if (tab_button)
  1449. {
  1450. mTotalTabWidth -= tab_button->getRect().getWidth();
  1451. tab_button->reshape(llclamp(fontp->getWidth(title) +
  1452. TAB_PADDING + tuple->mPadding,
  1453. mMinTabWidth, mMaxTabWidth),
  1454. tab_button->getRect().getHeight());
  1455. mTotalTabWidth += tab_button->getRect().getWidth();
  1456. tab_button->setLabelSelected(title);
  1457. tab_button->setLabelUnselected(title);
  1458. }
  1459. }
  1460. }
  1461. updateMaxScrollPos();
  1462. }
  1463. // static
  1464. void LLTabContainer::onTabBtn(void* userdata)
  1465. {
  1466. LLTabTuple* tuple = (LLTabTuple*)userdata;
  1467. if (tuple)
  1468. {
  1469. LLTabContainer* self = tuple->mTabContainer;
  1470. if (self)
  1471. {
  1472. self->selectTabPanel(tuple->mTabPanel);
  1473. }
  1474. tuple->mTabPanel->setFocus(true);
  1475. }
  1476. }
  1477. // static
  1478. void LLTabContainer::onCloseBtn(void* userdata)
  1479. {
  1480. LLTabContainer* self = (LLTabContainer*)userdata;
  1481. if (self && self->mCloseCallback)
  1482. {
  1483. self->mCloseCallback(self->mCallbackUserdata);
  1484. }
  1485. }
  1486. // static
  1487. void LLTabContainer::onNextBtn(void* userdata)
  1488. {
  1489. // Scroll tabs to the left
  1490. LLTabContainer* self = (LLTabContainer*)userdata;
  1491. if (!self) return;
  1492. if (!self->mScrolled)
  1493. {
  1494. self->scrollNext();
  1495. }
  1496. self->mScrolled = false;
  1497. if ((size_t)self->mCurrentTabIdx < self->mTabList.size() - 1)
  1498. {
  1499. self->selectNextTab();
  1500. }
  1501. }
  1502. // static
  1503. void LLTabContainer::onNextBtnHeld(void* userdata)
  1504. {
  1505. LLTabContainer* self = (LLTabContainer*)userdata;
  1506. if (self && self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
  1507. {
  1508. self->mScrollTimer.reset();
  1509. self->scrollNext();
  1510. if ((size_t)self->mCurrentTabIdx < self->mTabList.size() - 1)
  1511. {
  1512. self->selectNextTab();
  1513. }
  1514. self->mScrolled = true;
  1515. }
  1516. }
  1517. // static
  1518. void LLTabContainer::onPrevBtn(void* userdata)
  1519. {
  1520. LLTabContainer* self = (LLTabContainer*)userdata;
  1521. if (self)
  1522. {
  1523. if (!self->mScrolled)
  1524. {
  1525. self->scrollPrev();
  1526. }
  1527. self->mScrolled = false;
  1528. if (self->mCurrentTabIdx > 0)
  1529. {
  1530. self->selectPrevTab();
  1531. }
  1532. }
  1533. }
  1534. // static
  1535. void LLTabContainer::onJumpFirstBtn(void* userdata)
  1536. {
  1537. LLTabContainer* self = (LLTabContainer*)userdata;
  1538. if (self)
  1539. {
  1540. self->mScrollPos = 0;
  1541. }
  1542. }
  1543. // static
  1544. void LLTabContainer::onJumpLastBtn(void* userdata)
  1545. {
  1546. LLTabContainer* self = (LLTabContainer*)userdata;
  1547. if (self)
  1548. {
  1549. self->mScrollPos = self->mMaxScrollPos;
  1550. }
  1551. }
  1552. // static
  1553. void LLTabContainer::onPrevBtnHeld(void* userdata)
  1554. {
  1555. LLTabContainer* self = (LLTabContainer*)userdata;
  1556. if (self && self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
  1557. {
  1558. self->mScrollTimer.reset();
  1559. self->scrollPrev();
  1560. if (self->mCurrentTabIdx > 0)
  1561. {
  1562. self->selectPrevTab();
  1563. }
  1564. self->mScrolled = true;
  1565. }
  1566. }
  1567. //static
  1568. LLView* LLTabContainer::fromXML(LLXMLNodePtr nodep, LLView* parentp,
  1569. LLUICtrlFactory* factoryp)
  1570. {
  1571. std::string name = LL_TAB_CONTAINER_COMMON_TAG;
  1572. nodep->getAttributeString("name", name);
  1573. // Figure out if we are creating a vertical or horizontal tab container.
  1574. bool is_vertical = false;
  1575. TabPosition tab_position = LLTabContainer::TOP;
  1576. if (nodep->hasAttribute("tab_position"))
  1577. {
  1578. std::string tab_position_string;
  1579. nodep->getAttributeString("tab_position", tab_position_string);
  1580. LLStringUtil::toLower(tab_position_string);
  1581. if (tab_position_string == "top")
  1582. {
  1583. tab_position = LLTabContainer::TOP;
  1584. is_vertical = false;
  1585. }
  1586. else if (tab_position_string == "bottom")
  1587. {
  1588. tab_position = LLTabContainer::BOTTOM;
  1589. is_vertical = false;
  1590. }
  1591. else if (tab_position_string == "left")
  1592. {
  1593. is_vertical = true;
  1594. }
  1595. }
  1596. bool border = false;
  1597. nodep->getAttributeBool("border", border);
  1598. LLTabContainer* containerp = new LLTabContainer(name, LLRect::null,
  1599. tab_position, border,
  1600. is_vertical);
  1601. S32 tab_min_width = containerp->mMinTabWidth;
  1602. if (nodep->hasAttribute("tab_width"))
  1603. {
  1604. nodep->getAttributeS32("tab_width", tab_min_width);
  1605. }
  1606. else if (nodep->hasAttribute("tab_min_width"))
  1607. {
  1608. nodep->getAttributeS32("tab_min_width", tab_min_width);
  1609. }
  1610. S32 tab_max_width = containerp->mMaxTabWidth;
  1611. if (nodep->hasAttribute("tab_max_width"))
  1612. {
  1613. nodep->getAttributeS32("tab_max_width", tab_max_width);
  1614. }
  1615. containerp->setMinTabWidth(tab_min_width);
  1616. containerp->setMaxTabWidth(tab_max_width);
  1617. bool hidden = containerp->getTabsHidden();
  1618. nodep->getAttributeBool("hide_tabs", hidden);
  1619. containerp->setTabsHidden(hidden);
  1620. containerp->setPanelParameters(nodep, parentp);
  1621. if (LLFloater::getFloaterHost())
  1622. {
  1623. LLFloater::getFloaterHost()->setTabContainer(containerp);
  1624. }
  1625. #if 0
  1626. parentp->addChild(containerp);
  1627. #endif
  1628. // Add all tab panels.
  1629. std::string label;
  1630. for (LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();
  1631. childp = childp->getNextSibling())
  1632. {
  1633. LLView* controlp = factoryp->createCtrlWidget(containerp, childp);
  1634. // Yes, it may happen with bad XUI files. HB
  1635. if (!controlp)
  1636. {
  1637. continue;
  1638. }
  1639. LLPanel* panelp = controlp->asPanel();
  1640. if (panelp)
  1641. {
  1642. childp->getAttributeString("label", label);
  1643. if (label.empty())
  1644. {
  1645. label = panelp->getLabel();
  1646. }
  1647. bool placeholder = false;
  1648. childp->getAttributeBool("placeholder", placeholder);
  1649. containerp->addTabPanel(panelp, label, false, NULL, NULL, 0,
  1650. placeholder);
  1651. label.clear(); // Must be empty for next getAttributeString() call
  1652. }
  1653. }
  1654. containerp->selectFirstTab();
  1655. containerp->postBuild();
  1656. containerp->initButtons(); // Now that we have the correct rect
  1657. return containerp;
  1658. }
  1659. void LLTabContainer::initButtons()
  1660. {
  1661. // *HACK:
  1662. if (getRect().getHeight() == 0 || mPrevArrowBtn)
  1663. {
  1664. return; // Do not have a rect yet or already got called
  1665. }
  1666. std::string out_id;
  1667. std::string in_id;
  1668. if (mIsVertical)
  1669. {
  1670. // Left and right scroll arrows (for when there are too many tabs to show all at once).
  1671. S32 btn_top = getRect().getHeight();
  1672. S32 btn_top_lower = getRect().mBottom+TABCNTRV_ARROW_BTN_SIZE;
  1673. LLRect up_arrow_btn_rect;
  1674. up_arrow_btn_rect.setLeftTopAndSize(mMinTabWidth / 2, btn_top,
  1675. TABCNTRV_ARROW_BTN_SIZE,
  1676. TABCNTRV_ARROW_BTN_SIZE);
  1677. LLRect down_arrow_btn_rect;
  1678. down_arrow_btn_rect.setLeftTopAndSize(mMinTabWidth / 2, btn_top_lower,
  1679. TABCNTRV_ARROW_BTN_SIZE,
  1680. TABCNTRV_ARROW_BTN_SIZE);
  1681. out_id = "UIImgBtnScrollUpOutUUID";
  1682. in_id = "UIImgBtnScrollUpInUUID";
  1683. mPrevArrowBtn = new LLButton("Up Arrow", up_arrow_btn_rect, out_id,
  1684. in_id, NULL, &onPrevBtn, this, NULL);
  1685. mPrevArrowBtn->setFollowsTop();
  1686. mPrevArrowBtn->setFollowsLeft();
  1687. out_id = "UIImgBtnScrollDownOutUUID";
  1688. in_id = "UIImgBtnScrollDownInUUID";
  1689. mNextArrowBtn = new LLButton("Down Arrow", down_arrow_btn_rect, out_id,
  1690. in_id, NULL, &onNextBtn, this, NULL);
  1691. mNextArrowBtn->setFollowsBottom();
  1692. mNextArrowBtn->setFollowsLeft();
  1693. }
  1694. else // Horizontal
  1695. {
  1696. S32 arrow_fudge = 1; // match new art better
  1697. // tabs on bottom reserve room for resize handle (just in case)
  1698. if (getTabPosition() == BOTTOM)
  1699. {
  1700. mRightTabBtnOffset = RESIZE_HANDLE_WIDTH;
  1701. }
  1702. // Left and right scroll arrows (for when there are too many tabs to
  1703. // show all at once).
  1704. S32 btn_top = getTabPosition() == TOP ?
  1705. getRect().getHeight() - getTopBorderHeight() :
  1706. TABCNTR_ARROW_BTN_SIZE + 1;
  1707. LLRect left_arrow_btn_rect;
  1708. left_arrow_btn_rect.setLeftTopAndSize(LLPANEL_BORDER_WIDTH +
  1709. TABCNTR_ARROW_BTN_SIZE + 1,
  1710. btn_top + arrow_fudge,
  1711. TABCNTR_ARROW_BTN_SIZE,
  1712. TABCNTR_ARROW_BTN_SIZE);
  1713. LLRect jump_left_arrow_btn_rect;
  1714. jump_left_arrow_btn_rect.setLeftTopAndSize(LLPANEL_BORDER_WIDTH + 1,
  1715. btn_top + arrow_fudge,
  1716. TABCNTR_ARROW_BTN_SIZE,
  1717. TABCNTR_ARROW_BTN_SIZE);
  1718. S32 right_pad = TABCNTR_ARROW_BTN_SIZE + LLPANEL_BORDER_WIDTH + 1;
  1719. LLRect right_arrow_btn_rect;
  1720. right_arrow_btn_rect.setLeftTopAndSize(getRect().getWidth() -
  1721. mRightTabBtnOffset - right_pad -
  1722. TABCNTR_ARROW_BTN_SIZE,
  1723. btn_top + arrow_fudge,
  1724. TABCNTR_ARROW_BTN_SIZE,
  1725. TABCNTR_ARROW_BTN_SIZE);
  1726. LLRect jump_right_arrow_btn_rect;
  1727. jump_right_arrow_btn_rect.setLeftTopAndSize(getRect().getWidth() -
  1728. mRightTabBtnOffset -
  1729. right_pad,
  1730. btn_top + arrow_fudge,
  1731. TABCNTR_ARROW_BTN_SIZE,
  1732. TABCNTR_ARROW_BTN_SIZE);
  1733. static const LLFontGL* font = LLFontGL::getFontSansSerif();
  1734. out_id = "UIImgBtnJumpLeftOutUUID";
  1735. in_id = "UIImgBtnJumpLeftInUUID";
  1736. mJumpPrevArrowBtn = new LLButton("Jump Left Arrow",
  1737. jump_left_arrow_btn_rect, out_id,
  1738. in_id, NULL,
  1739. &LLTabContainer::onJumpFirstBtn,
  1740. this, font);
  1741. mJumpPrevArrowBtn->setFollowsLeft();
  1742. out_id = "UIImgBtnScrollLeftOutUUID";
  1743. in_id = "UIImgBtnScrollLeftInUUID";
  1744. mPrevArrowBtn = new LLButton("Left Arrow", left_arrow_btn_rect,
  1745. out_id, in_id, NULL,
  1746. &LLTabContainer::onPrevBtn,
  1747. this, font);
  1748. mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld);
  1749. mPrevArrowBtn->setFollowsLeft();
  1750. out_id = "UIImgBtnJumpRightOutUUID";
  1751. in_id = "UIImgBtnJumpRightInUUID";
  1752. mJumpNextArrowBtn = new LLButton("Jump Right Arrow",
  1753. jump_right_arrow_btn_rect,
  1754. out_id, in_id, NULL,
  1755. &LLTabContainer::onJumpLastBtn,
  1756. this, font);
  1757. mJumpNextArrowBtn->setFollowsRight();
  1758. out_id = "UIImgBtnScrollRightOutUUID";
  1759. in_id = "UIImgBtnScrollRightInUUID";
  1760. mNextArrowBtn = new LLButton("Right Arrow", right_arrow_btn_rect,
  1761. out_id, in_id, NULL,
  1762. &LLTabContainer::onNextBtn,
  1763. this, font);
  1764. mNextArrowBtn->setFollowsRight();
  1765. if (getTabPosition() == TOP)
  1766. {
  1767. mNextArrowBtn->setFollowsTop();
  1768. mPrevArrowBtn->setFollowsTop();
  1769. mJumpPrevArrowBtn->setFollowsTop();
  1770. mJumpNextArrowBtn->setFollowsTop();
  1771. }
  1772. else
  1773. {
  1774. mNextArrowBtn->setFollowsBottom();
  1775. mPrevArrowBtn->setFollowsBottom();
  1776. mJumpPrevArrowBtn->setFollowsBottom();
  1777. mJumpNextArrowBtn->setFollowsBottom();
  1778. }
  1779. }
  1780. mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld);
  1781. mPrevArrowBtn->setSaveToXML(false);
  1782. mPrevArrowBtn->setTabStop(false);
  1783. addChild(mPrevArrowBtn);
  1784. mNextArrowBtn->setHeldDownCallback(onNextBtnHeld);
  1785. mNextArrowBtn->setSaveToXML(false);
  1786. mNextArrowBtn->setTabStop(false);
  1787. addChild(mNextArrowBtn);
  1788. if (mJumpPrevArrowBtn)
  1789. {
  1790. mJumpPrevArrowBtn->setSaveToXML(false);
  1791. mJumpPrevArrowBtn->setTabStop(false);
  1792. addChild(mJumpPrevArrowBtn);
  1793. }
  1794. if (mJumpNextArrowBtn)
  1795. {
  1796. mJumpNextArrowBtn->setSaveToXML(false);
  1797. mJumpNextArrowBtn->setTabStop(false);
  1798. addChild(mJumpNextArrowBtn);
  1799. }
  1800. // Set default tab group to be panel contents
  1801. setDefaultTabGroup(1);
  1802. }
  1803. LLTabContainer::LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child)
  1804. {
  1805. for (tuple_list_t::iterator iter = mTabList.begin(),
  1806. end = mTabList.end();
  1807. iter != end; ++iter)
  1808. {
  1809. LLTabTuple* tuple = *iter;
  1810. if (tuple->mTabPanel == child)
  1811. {
  1812. return tuple;
  1813. }
  1814. }
  1815. return NULL;
  1816. }
  1817. void LLTabContainer::insertTuple(LLTabTuple* tuple,
  1818. eInsertionPoint insertion_point)
  1819. {
  1820. switch (insertion_point)
  1821. {
  1822. case START:
  1823. // Insert the new tab in the front of the list
  1824. mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
  1825. break;
  1826. case LEFT_OF_CURRENT:
  1827. {
  1828. // Insert the new tab before the current tab (but not before
  1829. // mLockedTabCount)
  1830. tuple_list_t::iterator current_iter = mTabList.begin() +
  1831. llmax(mLockedTabCount,
  1832. mCurrentTabIdx);
  1833. mTabList.insert(current_iter, tuple);
  1834. break;
  1835. }
  1836. case RIGHT_OF_CURRENT:
  1837. {
  1838. // Insert the new tab after the current tab (but not before
  1839. // mLockedTabCount)
  1840. tuple_list_t::iterator current_iter = mTabList.begin() +
  1841. llmax(mLockedTabCount,
  1842. mCurrentTabIdx + 1);
  1843. mTabList.insert(current_iter, tuple);
  1844. break;
  1845. }
  1846. case END:
  1847. default:
  1848. mTabList.push_back(tuple);
  1849. }
  1850. }
  1851. void LLTabContainer::updateMaxScrollPos()
  1852. {
  1853. bool no_scroll = true;
  1854. if (mIsVertical)
  1855. {
  1856. S32 tab_total_height = (gBtnHeight + TABCNTRV_PAD) * getTabCount();
  1857. S32 available_height = getRect().getHeight() - getTopBorderHeight();
  1858. if (tab_total_height > available_height)
  1859. {
  1860. S32 available_height_with_arrows =
  1861. getRect().getHeight() -
  1862. 2 * (TABCNTRV_ARROW_BTN_SIZE + 3 * TABCNTRV_PAD);
  1863. S32 additional_needed = tab_total_height -
  1864. available_height_with_arrows;
  1865. setMaxScrollPos((S32) ceil(additional_needed / F32(gBtnHeight)));
  1866. no_scroll = false;
  1867. }
  1868. }
  1869. else
  1870. {
  1871. S32 tab_space = 0;
  1872. S32 available_space = 0;
  1873. tab_space = mTotalTabWidth;
  1874. available_space = getRect().getWidth() - mRightTabBtnOffset -
  1875. 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_TAB_H_PAD);
  1876. if (tab_space > available_space)
  1877. {
  1878. S32 available_width_with_arrows = getRect().getWidth() -
  1879. mRightTabBtnOffset -
  1880. 2 * TABCNTR_TAB_BTN_MARGIN;
  1881. // Subtract off reserved portion on left
  1882. available_width_with_arrows -= TABCNTR_TAB_PARTIAL_WIDTH;
  1883. S32 running_tab_width = 0;
  1884. setMaxScrollPos(getTabCount());
  1885. for (tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(),
  1886. rend = mTabList.rend();
  1887. tab_it != rend; ++tab_it)
  1888. {
  1889. running_tab_width += (*tab_it)->mButton->getRect().getWidth();
  1890. if (running_tab_width > available_width_with_arrows)
  1891. {
  1892. break;
  1893. }
  1894. setMaxScrollPos(getMaxScrollPos() - 1);
  1895. }
  1896. // In case last tab does not actually fit on screen, make it the
  1897. // last scrolling position
  1898. setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1));
  1899. no_scroll = false;
  1900. }
  1901. }
  1902. if (no_scroll)
  1903. {
  1904. setMaxScrollPos(0);
  1905. setScrollPos(0);
  1906. }
  1907. if (getScrollPos() > getMaxScrollPos())
  1908. {
  1909. // Maybe just enforce this via limits in setScrollPos instead ?
  1910. setScrollPos(getMaxScrollPos());
  1911. }
  1912. }
  1913. void LLTabContainer::commitHoveredButton(S32 x, S32 y)
  1914. {
  1915. if (hasMouseCapture())
  1916. {
  1917. for (tuple_list_t::iterator iter = mTabList.begin(),
  1918. end = mTabList.end();
  1919. iter != end; ++iter)
  1920. {
  1921. LLTabTuple* tuple = *iter;
  1922. if (!tuple || !tuple->mTabPanel) continue;
  1923. LLButton* tab_button = tuple->mButton;
  1924. if (!tab_button) continue;
  1925. tab_button->setVisible(true);
  1926. S32 local_x = x - tab_button->getRect().mLeft;
  1927. S32 local_y = y - tab_button->getRect().mBottom;
  1928. if (tab_button->pointInView(local_x, local_y) &&
  1929. tab_button->getEnabled() && !tuple->mTabPanel->getVisible())
  1930. {
  1931. tab_button->onCommit();
  1932. }
  1933. }
  1934. }
  1935. }