PageRenderTime 106ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llui/llaccordionctrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 914 lines | 702 code | 147 blank | 65 comment | 136 complexity | 1fb24b5e1f0ffd8dc94a233dfe305310 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llaccordionctrl.cpp
  3. * @brief Accordion panel implementation
  4. *
  5. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llaccordionctrl.h"
  28. #include "llaccordionctrltab.h"
  29. #include "lluictrlfactory.h" // builds floaters from XML
  30. #include "llwindow.h"
  31. #include "llfocusmgr.h"
  32. #include "lllocalcliprect.h"
  33. #include "boost/bind.hpp"
  34. static const S32 DRAGGER_BAR_MARGIN = 4;
  35. static const S32 DRAGGER_BAR_HEIGHT = 5;
  36. static const S32 BORDER_MARGIN = 2;
  37. static const S32 PARENT_BORDER_MARGIN = 5;
  38. static const S32 panel_delta = DRAGGER_BAR_MARGIN; // Distanse between two panels
  39. static const S32 HORIZONTAL_MULTIPLE = 8;
  40. static const S32 VERTICAL_MULTIPLE = 16;
  41. static const F32 MIN_AUTO_SCROLL_RATE = 120.f;
  42. static const F32 MAX_AUTO_SCROLL_RATE = 500.f;
  43. static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f;
  44. // LLAccordionCtrl =================================================================|
  45. static LLDefaultChildRegistry::Register<LLAccordionCtrl> t2("accordion");
  46. LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params)
  47. , mFitParent(params.fit_parent)
  48. , mAutoScrolling( false )
  49. , mAutoScrollRate( 0.f )
  50. , mSelectedTab( NULL )
  51. , mTabComparator( NULL )
  52. , mNoVisibleTabsHelpText(NULL)
  53. , mNoVisibleTabsOrigString(params.no_visible_tabs_text.initial_value().asString())
  54. {
  55. initNoTabsWidget(params.no_matched_tabs_text);
  56. mSingleExpansion = params.single_expansion;
  57. if(mFitParent && !mSingleExpansion)
  58. {
  59. llinfos << "fit_parent works best when combined with single_expansion" << llendl;
  60. }
  61. }
  62. LLAccordionCtrl::LLAccordionCtrl() : LLPanel()
  63. , mAutoScrolling( false )
  64. , mAutoScrollRate( 0.f )
  65. , mSelectedTab( NULL )
  66. , mNoVisibleTabsHelpText(NULL)
  67. {
  68. initNoTabsWidget(LLTextBox::Params());
  69. mSingleExpansion = false;
  70. mFitParent = false;
  71. buildFromFile( "accordion_parent.xml");
  72. }
  73. //---------------------------------------------------------------------------------
  74. void LLAccordionCtrl::draw()
  75. {
  76. if (mAutoScrolling)
  77. {
  78. // add acceleration to autoscroll
  79. mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), MAX_AUTO_SCROLL_RATE);
  80. }
  81. else
  82. {
  83. // reset to minimum for next time
  84. mAutoScrollRate = MIN_AUTO_SCROLL_RATE;
  85. }
  86. // clear this flag to be set on next call to autoScroll
  87. mAutoScrolling = false;
  88. LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
  89. LLLocalClipRect clip(local_rect);
  90. LLPanel::draw();
  91. }
  92. //---------------------------------------------------------------------------------
  93. BOOL LLAccordionCtrl::postBuild()
  94. {
  95. static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
  96. LLRect scroll_rect;
  97. scroll_rect.setOriginAndSize(
  98. getRect().getWidth() - scrollbar_size,
  99. 1,
  100. scrollbar_size,
  101. getRect().getHeight() - 1);
  102. LLScrollbar::Params sbparams;
  103. sbparams.name("scrollable vertical");
  104. sbparams.rect(scroll_rect);
  105. sbparams.orientation(LLScrollbar::VERTICAL);
  106. sbparams.doc_size(mInnerRect.getHeight());
  107. sbparams.doc_pos(0);
  108. sbparams.page_size(mInnerRect.getHeight());
  109. sbparams.step_size(VERTICAL_MULTIPLE);
  110. sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
  111. sbparams.change_callback(boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2));
  112. mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams);
  113. LLView::addChild( mScrollbar );
  114. mScrollbar->setVisible( false );
  115. mScrollbar->setFollowsRight();
  116. mScrollbar->setFollowsTop();
  117. mScrollbar->setFollowsBottom();
  118. //if it was created from xml...
  119. std::vector<LLUICtrl*> accordion_tabs;
  120. for(child_list_const_iter_t it = getChildList()->begin();
  121. getChildList()->end() != it; ++it)
  122. {
  123. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*it);
  124. if(accordion_tab == NULL)
  125. continue;
  126. if(std::find(mAccordionTabs.begin(),mAccordionTabs.end(),accordion_tab) == mAccordionTabs.end())
  127. {
  128. accordion_tabs.push_back(accordion_tab);
  129. }
  130. }
  131. for(std::vector<LLUICtrl*>::reverse_iterator it = accordion_tabs.rbegin();it!=accordion_tabs.rend();++it)
  132. addCollapsibleCtrl(*it);
  133. arrange ();
  134. if(mSingleExpansion)
  135. {
  136. if(!mAccordionTabs[0]->getDisplayChildren())
  137. mAccordionTabs[0]->setDisplayChildren(true);
  138. for(size_t i=1;i<mAccordionTabs.size();++i)
  139. {
  140. if(mAccordionTabs[i]->getDisplayChildren())
  141. mAccordionTabs[i]->setDisplayChildren(false);
  142. }
  143. }
  144. updateNoTabsHelpTextVisibility();
  145. return TRUE;
  146. }
  147. //---------------------------------------------------------------------------------
  148. LLAccordionCtrl::~LLAccordionCtrl()
  149. {
  150. mAccordionTabs.clear();
  151. }
  152. //---------------------------------------------------------------------------------
  153. void LLAccordionCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
  154. {
  155. // adjust our rectangle
  156. LLRect rcLocal = getRect();
  157. rcLocal.mRight = rcLocal.mLeft + width;
  158. rcLocal.mTop = rcLocal.mBottom + height;
  159. // get textbox a chance to reshape its content
  160. mNoVisibleTabsHelpText->reshape(width, height, called_from_parent);
  161. setRect(rcLocal);
  162. // assume that help text is always fit accordion.
  163. // necessary text paddings can be set via h_pad and v_pad
  164. mNoVisibleTabsHelpText->setRect(getLocalRect());
  165. arrange();
  166. }
  167. //---------------------------------------------------------------------------------
  168. BOOL LLAccordionCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
  169. {
  170. return LLPanel::handleRightMouseDown(x, y, mask);
  171. }
  172. //---------------------------------------------------------------------------------
  173. void LLAccordionCtrl::shiftAccordionTabs(S16 panel_num, S32 delta)
  174. {
  175. for(size_t i = panel_num; i < mAccordionTabs.size(); i++ )
  176. {
  177. ctrlShiftVertical(mAccordionTabs[i],delta);
  178. }
  179. }
  180. //---------------------------------------------------------------------------------
  181. void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num)
  182. {
  183. if(mSingleExpansion)
  184. {
  185. for(size_t i=0;i<mAccordionTabs.size();++i)
  186. {
  187. if(i==panel_num)
  188. continue;
  189. if(mAccordionTabs[i]->getDisplayChildren())
  190. mAccordionTabs[i]->setDisplayChildren(false);
  191. }
  192. }
  193. arrange();
  194. }
  195. void LLAccordionCtrl::show_hide_scrollbar(S32 width, S32 height)
  196. {
  197. calcRecuiredHeight();
  198. if(getRecuiredHeight() > height )
  199. showScrollbar(width,height);
  200. else
  201. hideScrollbar(width,height);
  202. }
  203. void LLAccordionCtrl::showScrollbar(S32 width, S32 height)
  204. {
  205. bool was_visible = mScrollbar->getVisible();
  206. mScrollbar->setVisible(true);
  207. static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
  208. ctrlSetLeftTopAndSize(mScrollbar
  209. ,width-scrollbar_size - PARENT_BORDER_MARGIN/2
  210. ,height-PARENT_BORDER_MARGIN
  211. ,scrollbar_size
  212. ,height-2*PARENT_BORDER_MARGIN);
  213. mScrollbar->setPageSize(height);
  214. mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos());
  215. if(was_visible)
  216. {
  217. S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1);
  218. mScrollbar->setDocPos(scroll_pos);
  219. }
  220. }
  221. void LLAccordionCtrl::hideScrollbar( S32 width, S32 height )
  222. {
  223. if(mScrollbar->getVisible() == false)
  224. return;
  225. mScrollbar->setVisible(false);
  226. static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
  227. S32 panel_width = width - 2*BORDER_MARGIN;
  228. //reshape all accordeons and shift all draggers
  229. for(size_t i=0;i<mAccordionTabs.size();++i)
  230. {
  231. LLRect panel_rect = mAccordionTabs[i]->getRect();
  232. ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_rect.mTop,panel_width,panel_rect.getHeight());
  233. }
  234. mScrollbar->setDocPos(0);
  235. if(mAccordionTabs.size()>0)
  236. {
  237. S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel
  238. S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop;
  239. shiftAccordionTabs(0,diff);
  240. }
  241. }
  242. //---------------------------------------------------------------------------------
  243. S32 LLAccordionCtrl::calcRecuiredHeight()
  244. {
  245. S32 rec_height = 0;
  246. std::vector<LLAccordionCtrlTab*>::iterator panel;
  247. for(panel=mAccordionTabs.begin(); panel!=mAccordionTabs.end(); ++panel)
  248. {
  249. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(*panel);
  250. if(accordion_tab && accordion_tab->getVisible())
  251. {
  252. rec_height += accordion_tab->getRect().getHeight();
  253. }
  254. }
  255. mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN);
  256. return mInnerRect.getHeight();
  257. }
  258. //---------------------------------------------------------------------------------
  259. void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height)
  260. {
  261. if(!panel)
  262. return;
  263. LLRect panel_rect = panel->getRect();
  264. panel_rect.setLeftTopAndSize( left, top, width, height);
  265. panel->reshape( width, height, 1);
  266. panel->setRect(panel_rect);
  267. }
  268. void LLAccordionCtrl::ctrlShiftVertical(LLView* panel,S32 delta)
  269. {
  270. if(!panel)
  271. return;
  272. panel->translate(0,delta);
  273. }
  274. //---------------------------------------------------------------------------------
  275. void LLAccordionCtrl::addCollapsibleCtrl(LLView* view)
  276. {
  277. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view);
  278. if(!accordion_tab)
  279. return;
  280. if(std::find(beginChild(), endChild(), accordion_tab) == endChild())
  281. addChild(accordion_tab);
  282. mAccordionTabs.push_back(accordion_tab);
  283. accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) );
  284. arrange();
  285. }
  286. void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view)
  287. {
  288. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view);
  289. if(!accordion_tab)
  290. return;
  291. if(std::find(beginChild(), endChild(), accordion_tab) != endChild())
  292. removeChild(accordion_tab);
  293. for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin();
  294. iter != mAccordionTabs.end(); ++iter)
  295. {
  296. if (accordion_tab == (*iter))
  297. {
  298. mAccordionTabs.erase(iter);
  299. break;
  300. }
  301. }
  302. // if removed is selected - reset selection
  303. if (mSelectedTab == view)
  304. {
  305. mSelectedTab = NULL;
  306. }
  307. }
  308. void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params)
  309. {
  310. LLTextBox::Params tp = tb_params;
  311. tp.rect(getLocalRect());
  312. mNoMatchedTabsOrigString = tp.initial_value().asString();
  313. mNoVisibleTabsHelpText = LLUICtrlFactory::create<LLTextBox>(tp, this);
  314. }
  315. void LLAccordionCtrl::updateNoTabsHelpTextVisibility()
  316. {
  317. bool visible_exists = false;
  318. std::vector<LLAccordionCtrlTab*>::const_iterator it = mAccordionTabs.begin();
  319. const std::vector<LLAccordionCtrlTab*>::const_iterator it_end = mAccordionTabs.end();
  320. for (; it != it_end; ++it)
  321. {
  322. if ((*it)->getVisible())
  323. {
  324. visible_exists = true;
  325. break;
  326. }
  327. }
  328. mNoVisibleTabsHelpText->setVisible(!visible_exists);
  329. }
  330. void LLAccordionCtrl::arrangeSinge()
  331. {
  332. S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
  333. S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
  334. S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel
  335. S32 panel_height;
  336. S32 collapsed_height = 0;
  337. for(size_t i=0;i<mAccordionTabs.size();++i)
  338. {
  339. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
  340. if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
  341. continue;
  342. if(!accordion_tab->isExpanded() )
  343. {
  344. collapsed_height+=mAccordionTabs[i]->getRect().getHeight();
  345. }
  346. }
  347. S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height;
  348. for(size_t i=0;i<mAccordionTabs.size();++i)
  349. {
  350. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
  351. if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
  352. continue;
  353. if(!accordion_tab->isExpanded() )
  354. {
  355. panel_height = accordion_tab->getRect().getHeight();
  356. }
  357. else
  358. {
  359. if(mFitParent)
  360. {
  361. panel_height = expanded_height;
  362. }
  363. else
  364. {
  365. if(accordion_tab->getAccordionView())
  366. {
  367. panel_height = accordion_tab->getAccordionView()->getRect().getHeight() +
  368. accordion_tab->getHeaderHeight() + 2*BORDER_MARGIN;
  369. }
  370. else
  371. {
  372. panel_height = accordion_tab->getRect().getHeight();
  373. }
  374. }
  375. }
  376. // make sure at least header is shown
  377. panel_height = llmax(panel_height, accordion_tab->getHeaderHeight());
  378. ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height);
  379. panel_top-=mAccordionTabs[i]->getRect().getHeight();
  380. }
  381. show_hide_scrollbar(getRect().getWidth(), getRect().getHeight());
  382. updateLayout(getRect().getWidth(), getRect().getHeight());
  383. }
  384. void LLAccordionCtrl::arrangeMultiple()
  385. {
  386. S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
  387. S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
  388. S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel
  389. //Calculate params
  390. for(size_t i = 0; i < mAccordionTabs.size(); i++ )
  391. {
  392. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
  393. if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
  394. continue;
  395. if(!accordion_tab->isExpanded() )
  396. {
  397. ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight());
  398. panel_top-=mAccordionTabs[i]->getRect().getHeight();
  399. }
  400. else
  401. {
  402. S32 panel_height = accordion_tab->getRect().getHeight();
  403. if(mFitParent)
  404. {
  405. // all expanded tabs will have equal height
  406. panel_height = calcExpandedTabHeight(i, panel_top);
  407. ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height);
  408. // try to make accordion tab fit accordion view height.
  409. // Accordion View should implement getRequiredRect() and provide valid height
  410. S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight();
  411. optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN;
  412. if(optimal_height < panel_height)
  413. {
  414. panel_height = optimal_height;
  415. }
  416. // minimum tab height is equal to header height
  417. if(mAccordionTabs[i]->getHeaderHeight() > panel_height)
  418. {
  419. panel_height = mAccordionTabs[i]->getHeaderHeight();
  420. }
  421. }
  422. ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height);
  423. panel_top-=panel_height;
  424. }
  425. }
  426. show_hide_scrollbar(getRect().getWidth(),getRect().getHeight());
  427. updateLayout(getRect().getWidth(),getRect().getHeight());
  428. }
  429. void LLAccordionCtrl::arrange()
  430. {
  431. updateNoTabsHelpTextVisibility();
  432. if( mAccordionTabs.size() == 0)
  433. {
  434. //We do not arrange if we do not have what should be arranged
  435. return;
  436. }
  437. if(mAccordionTabs.size() == 1)
  438. {
  439. S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
  440. S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel
  441. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[0]);
  442. LLRect panel_rect = accordion_tab->getRect();
  443. S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN;
  444. if (accordion_tab->getFitParent())
  445. panel_height = accordion_tab->getRect().getHeight();
  446. ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height);
  447. show_hide_scrollbar(getRect().getWidth(),getRect().getHeight());
  448. return;
  449. }
  450. if(mSingleExpansion)
  451. arrangeSinge ();
  452. else
  453. arrangeMultiple ();
  454. }
  455. //---------------------------------------------------------------------------------
  456. BOOL LLAccordionCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks )
  457. {
  458. if(LLPanel::handleScrollWheel(x,y,clicks))
  459. return TRUE;
  460. if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) )
  461. return TRUE;
  462. return false;
  463. }
  464. BOOL LLAccordionCtrl::handleKeyHere (KEY key, MASK mask)
  465. {
  466. if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) )
  467. return TRUE;
  468. return LLPanel::handleKeyHere(key,mask);
  469. }
  470. BOOL LLAccordionCtrl::handleDragAndDrop (S32 x, S32 y, MASK mask,
  471. BOOL drop,
  472. EDragAndDropType cargo_type,
  473. void* cargo_data,
  474. EAcceptance* accept,
  475. std::string& tooltip_msg)
  476. {
  477. // Scroll folder view if needed. Never accepts a drag or drop.
  478. *accept = ACCEPT_NO;
  479. BOOL handled = autoScroll(x, y);
  480. if( !handled )
  481. {
  482. handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type,
  483. cargo_data, accept, tooltip_msg) != NULL;
  484. }
  485. return TRUE;
  486. }
  487. BOOL LLAccordionCtrl::autoScroll (S32 x, S32 y)
  488. {
  489. static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
  490. bool scrolling = false;
  491. if( mScrollbar->getVisible() )
  492. {
  493. LLRect rect_local( 0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0 );
  494. LLRect screen_local_extents;
  495. // clip rect against root view
  496. screenRectToLocal(getRootView()->getLocalRect(), &screen_local_extents);
  497. rect_local.intersectWith(screen_local_extents);
  498. // autoscroll region should take up no more than one third of visible scroller area
  499. S32 auto_scroll_region_height = llmin(rect_local.getHeight() / 3, 10);
  500. S32 auto_scroll_speed = llround(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32());
  501. LLRect bottom_scroll_rect = screen_local_extents;
  502. bottom_scroll_rect.mTop = rect_local.mBottom + auto_scroll_region_height;
  503. if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax()) )
  504. {
  505. mScrollbar->setDocPos( mScrollbar->getDocPos() + auto_scroll_speed );
  506. mAutoScrolling = true;
  507. scrolling = true;
  508. }
  509. LLRect top_scroll_rect = screen_local_extents;
  510. top_scroll_rect.mBottom = rect_local.mTop - auto_scroll_region_height;
  511. if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() > 0) )
  512. {
  513. mScrollbar->setDocPos( mScrollbar->getDocPos() - auto_scroll_speed );
  514. mAutoScrolling = true;
  515. scrolling = true;
  516. }
  517. }
  518. return scrolling;
  519. }
  520. void LLAccordionCtrl::updateLayout (S32 width, S32 height)
  521. {
  522. S32 panel_top = height - BORDER_MARGIN ;
  523. if(mScrollbar->getVisible())
  524. panel_top+=mScrollbar->getDocPos();
  525. S32 panel_width = width - 2*BORDER_MARGIN;
  526. static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
  527. if(mScrollbar->getVisible())
  528. panel_width-=scrollbar_size;
  529. //set sizes for first panels and dragbars
  530. for(size_t i=0;i<mAccordionTabs.size();++i)
  531. {
  532. if(!mAccordionTabs[i]->getVisible())
  533. continue;
  534. LLRect panel_rect = mAccordionTabs[i]->getRect();
  535. ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight());
  536. panel_top-=panel_rect.getHeight();
  537. }
  538. }
  539. void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*)
  540. {
  541. updateLayout(getRect().getWidth(),getRect().getHeight());
  542. }
  543. void LLAccordionCtrl::onOpen (const LLSD& key)
  544. {
  545. for(size_t i=0;i<mAccordionTabs.size();++i)
  546. {
  547. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
  548. LLPanel* panel = dynamic_cast<LLPanel*>(accordion_tab->getAccordionView());
  549. if(panel!=NULL)
  550. {
  551. panel->onOpen(key);
  552. }
  553. }
  554. }
  555. S32 LLAccordionCtrl::notifyParent(const LLSD& info)
  556. {
  557. if(info.has("action"))
  558. {
  559. std::string str_action = info["action"];
  560. if(str_action == "size_changes")
  561. {
  562. //
  563. arrange();
  564. return 1;
  565. }
  566. else if(str_action == "select_next")
  567. {
  568. for(size_t i=0;i<mAccordionTabs.size();++i)
  569. {
  570. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
  571. if(accordion_tab->hasFocus())
  572. {
  573. while(++i<mAccordionTabs.size())
  574. {
  575. if(mAccordionTabs[i]->getVisible())
  576. break;
  577. }
  578. if(i<mAccordionTabs.size())
  579. {
  580. accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
  581. accordion_tab->notify(LLSD().with("action","select_first"));
  582. return 1;
  583. }
  584. break;
  585. }
  586. }
  587. return 0;
  588. }
  589. else if(str_action == "select_prev")
  590. {
  591. for(size_t i=0;i<mAccordionTabs.size();++i)
  592. {
  593. LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
  594. if(accordion_tab->hasFocus() && i>0)
  595. {
  596. bool prev_visible_tab_found = false;
  597. while(i>0)
  598. {
  599. if(mAccordionTabs[--i]->getVisible())
  600. {
  601. prev_visible_tab_found = true;
  602. break;
  603. }
  604. }
  605. if (prev_visible_tab_found)
  606. {
  607. accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
  608. accordion_tab->notify(LLSD().with("action","select_last"));
  609. return 1;
  610. }
  611. break;
  612. }
  613. }
  614. return 0;
  615. }
  616. else if(str_action == "select_current")
  617. {
  618. for(size_t i=0;i<mAccordionTabs.size();++i)
  619. {
  620. // Set selection to the currently focused tab.
  621. if(mAccordionTabs[i]->hasFocus())
  622. {
  623. if (mAccordionTabs[i] != mSelectedTab)
  624. {
  625. if (mSelectedTab)
  626. {
  627. mSelectedTab->setSelected(false);
  628. }
  629. mSelectedTab = mAccordionTabs[i];
  630. mSelectedTab->setSelected(true);
  631. }
  632. return 1;
  633. }
  634. }
  635. return 0;
  636. }
  637. else if(str_action == "deselect_current")
  638. {
  639. // Reset selection to the currently selected tab.
  640. if (mSelectedTab)
  641. {
  642. mSelectedTab->setSelected(false);
  643. mSelectedTab = NULL;
  644. return 1;
  645. }
  646. return 0;
  647. }
  648. }
  649. else if (info.has("scrollToShowRect"))
  650. {
  651. LLRect screen_rc, local_rc;
  652. screen_rc.setValue(info["scrollToShowRect"]);
  653. screenRectToLocal(screen_rc, &local_rc);
  654. // Translate to parent coordinatess to check if we are in visible rectangle
  655. local_rc.translate( getRect().mLeft, getRect().mBottom );
  656. if ( !getRect().contains (local_rc) )
  657. {
  658. // Back to local coords and calculate position for scroller
  659. S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom;
  660. S32 top = mScrollbar->getDocPos() - local_rc.mTop + getRect().mTop;
  661. S32 scroll_pos = llclamp(mScrollbar->getDocPos(),
  662. bottom, // min vertical scroll
  663. top); // max vertical scroll
  664. mScrollbar->setDocPos( scroll_pos );
  665. }
  666. return 1;
  667. }
  668. else if (info.has("child_visibility_change"))
  669. {
  670. BOOL new_visibility = info["child_visibility_change"];
  671. if (new_visibility)
  672. {
  673. // there is at least one visible tab
  674. mNoVisibleTabsHelpText->setVisible(FALSE);
  675. }
  676. else
  677. {
  678. // it could be the latest visible tab, check all of them
  679. updateNoTabsHelpTextVisibility();
  680. }
  681. }
  682. return LLPanel::notifyParent(info);
  683. }
  684. void LLAccordionCtrl::reset ()
  685. {
  686. if(mScrollbar)
  687. mScrollbar->setDocPos(0);
  688. }
  689. void LLAccordionCtrl::expandDefaultTab()
  690. {
  691. if (mAccordionTabs.size() > 0)
  692. {
  693. LLAccordionCtrlTab* tab = mAccordionTabs.front();
  694. if (!tab->getDisplayChildren())
  695. {
  696. tab->setDisplayChildren(true);
  697. }
  698. for (size_t i = 1; i < mAccordionTabs.size(); ++i)
  699. {
  700. tab = mAccordionTabs[i];
  701. if (tab->getDisplayChildren())
  702. {
  703. tab->setDisplayChildren(false);
  704. }
  705. }
  706. arrange();
  707. }
  708. }
  709. void LLAccordionCtrl::sort()
  710. {
  711. if (!mTabComparator)
  712. {
  713. llwarns << "No comparator specified for sorting accordion tabs." << llendl;
  714. return;
  715. }
  716. std::sort(mAccordionTabs.begin(), mAccordionTabs.end(), LLComparatorAdaptor(*mTabComparator));
  717. arrange();
  718. }
  719. void LLAccordionCtrl::setFilterSubString(const std::string& filter_string)
  720. {
  721. LLStringUtil::format_map_t args;
  722. args["[SEARCH_TERM]"] = LLURI::escape(filter_string);
  723. std::string text = filter_string.empty() ? mNoVisibleTabsOrigString : mNoMatchedTabsOrigString;
  724. LLStringUtil::format(text, args);
  725. mNoVisibleTabsHelpText->setValue(text);
  726. }
  727. const LLAccordionCtrlTab* LLAccordionCtrl::getExpandedTab() const
  728. {
  729. typedef std::vector<LLAccordionCtrlTab*>::const_iterator tabs_const_iterator;
  730. const LLAccordionCtrlTab* result = 0;
  731. for (tabs_const_iterator i = mAccordionTabs.begin(); i != mAccordionTabs.end(); ++i)
  732. {
  733. if ((*i)->isExpanded())
  734. {
  735. result = *i;
  736. break;
  737. }
  738. }
  739. return result;
  740. }
  741. S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */)
  742. {
  743. if(tab_index < 0)
  744. {
  745. return available_height;
  746. }
  747. S32 collapsed_tabs_height = 0;
  748. S32 num_expanded = 0;
  749. for(size_t n = tab_index; n < mAccordionTabs.size(); ++n)
  750. {
  751. if(!mAccordionTabs[n]->isExpanded())
  752. {
  753. collapsed_tabs_height += mAccordionTabs[n]->getHeaderHeight();
  754. }
  755. else
  756. {
  757. ++num_expanded;
  758. }
  759. }
  760. if(0 == num_expanded)
  761. {
  762. return available_height;
  763. }
  764. S32 expanded_tab_height = available_height - collapsed_tabs_height - BORDER_MARGIN; // top BORDER_MARGIN is added in arrange(), here we add bottom BORDER_MARGIN
  765. expanded_tab_height /= num_expanded;
  766. return expanded_tab_height;
  767. }