PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/lllayoutstack.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 800 lines | 649 code | 95 blank | 56 comment | 111 complexity | 44cd588d9f2320f16c68a48d62cc69e3 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lllayoutstack.cpp
  3. * @brief LLLayout class - dynamic stacking of UI elements
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. // Opaque view with a background and a border. Can contain LLUICtrls.
  27. #include "linden_common.h"
  28. #include "lllayoutstack.h"
  29. #include "lllocalcliprect.h"
  30. #include "llpanel.h"
  31. #include "llresizebar.h"
  32. #include "llcriticaldamp.h"
  33. #include "boost/foreach.hpp"
  34. static const F32 MIN_FRACTIONAL_SIZE = 0.0001f;
  35. static const F32 MAX_FRACTIONAL_SIZE = 1.f;
  36. static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");
  37. static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel");
  38. void LLLayoutStack::OrientationNames::declareValues()
  39. {
  40. declare("horizontal", HORIZONTAL);
  41. declare("vertical", VERTICAL);
  42. }
  43. //
  44. // LLLayoutPanel
  45. //
  46. LLLayoutPanel::Params::Params()
  47. : expanded_min_dim("expanded_min_dim", 0),
  48. min_dim("min_dim", -1),
  49. user_resize("user_resize", false),
  50. auto_resize("auto_resize", true)
  51. {
  52. addSynonym(min_dim, "min_width");
  53. addSynonym(min_dim, "min_height");
  54. }
  55. LLLayoutPanel::LLLayoutPanel(const Params& p)
  56. : LLPanel(p),
  57. mExpandedMinDim(p.expanded_min_dim.isProvided() ? p.expanded_min_dim : p.min_dim),
  58. mMinDim(p.min_dim),
  59. mAutoResize(p.auto_resize),
  60. mUserResize(p.user_resize),
  61. mCollapsed(FALSE),
  62. mCollapseAmt(0.f),
  63. mVisibleAmt(1.f), // default to fully visible
  64. mResizeBar(NULL),
  65. mFractionalSize(MIN_FRACTIONAL_SIZE),
  66. mTargetDim(0),
  67. mIgnoreReshape(false),
  68. mOrientation(LLLayoutStack::HORIZONTAL)
  69. {
  70. // panels initialized as hidden should not start out partially visible
  71. if (!getVisible())
  72. {
  73. mVisibleAmt = 0.f;
  74. }
  75. }
  76. void LLLayoutPanel::initFromParams(const Params& p)
  77. {
  78. LLPanel::initFromParams(p);
  79. setFollowsNone();
  80. }
  81. LLLayoutPanel::~LLLayoutPanel()
  82. {
  83. // probably not necessary, but...
  84. delete mResizeBar;
  85. mResizeBar = NULL;
  86. }
  87. F32 LLLayoutPanel::getAutoResizeFactor() const
  88. {
  89. return mVisibleAmt * (1.f - mCollapseAmt);
  90. }
  91. F32 LLLayoutPanel::getVisibleAmount() const
  92. {
  93. return mVisibleAmt;
  94. }
  95. S32 LLLayoutPanel::getLayoutDim() const
  96. {
  97. return llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL)
  98. ? getRect().getWidth()
  99. : getRect().getHeight()));
  100. }
  101. S32 LLLayoutPanel::getVisibleDim() const
  102. {
  103. F32 min_dim = getRelevantMinDim();
  104. return llround(mVisibleAmt
  105. * (min_dim
  106. + (((F32)mTargetDim - min_dim) * (1.f - mCollapseAmt))));
  107. }
  108. void LLLayoutPanel::setOrientation( LLLayoutStack::ELayoutOrientation orientation )
  109. {
  110. mOrientation = orientation;
  111. S32 layout_dim = llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL)
  112. ? getRect().getWidth()
  113. : getRect().getHeight()));
  114. mTargetDim = llmax(layout_dim, getMinDim());
  115. }
  116. void LLLayoutPanel::setVisible( BOOL visible )
  117. {
  118. if (visible != getVisible())
  119. {
  120. LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent());
  121. if (stackp)
  122. {
  123. stackp->mNeedsLayout = true;
  124. }
  125. }
  126. LLPanel::setVisible(visible);
  127. }
  128. void LLLayoutPanel::reshape( S32 width, S32 height, BOOL called_from_parent /*= TRUE*/ )
  129. {
  130. if (width == getRect().getWidth() && height == getRect().getHeight()) return;
  131. if (!mIgnoreReshape && mAutoResize == false)
  132. {
  133. mTargetDim = (mOrientation == LLLayoutStack::HORIZONTAL) ? width : height;
  134. LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent());
  135. if (stackp)
  136. {
  137. stackp->mNeedsLayout = true;
  138. }
  139. }
  140. LLPanel::reshape(width, height, called_from_parent);
  141. }
  142. void LLLayoutPanel::handleReshape(const LLRect& new_rect, bool by_user)
  143. {
  144. LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent());
  145. if (stackp)
  146. {
  147. stackp->mNeedsLayout = true;
  148. if (by_user)
  149. {
  150. // tell layout stack to account for new shape
  151. stackp->updatePanelRect(this, new_rect);
  152. }
  153. }
  154. LLPanel::handleReshape(new_rect, by_user);
  155. }
  156. //
  157. // LLLayoutStack
  158. //
  159. LLLayoutStack::Params::Params()
  160. : orientation("orientation"),
  161. animate("animate", true),
  162. clip("clip", true),
  163. open_time_constant("open_time_constant", 0.02f),
  164. close_time_constant("close_time_constant", 0.03f),
  165. resize_bar_overlap("resize_bar_overlap", 1),
  166. border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))
  167. {}
  168. LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p)
  169. : LLView(p),
  170. mPanelSpacing(p.border_size),
  171. mOrientation(p.orientation),
  172. mAnimate(p.animate),
  173. mAnimatedThisFrame(false),
  174. mNeedsLayout(true),
  175. mClip(p.clip),
  176. mOpenTimeConstant(p.open_time_constant),
  177. mCloseTimeConstant(p.close_time_constant),
  178. mResizeBarOverlap(p.resize_bar_overlap)
  179. {}
  180. LLLayoutStack::~LLLayoutStack()
  181. {
  182. e_panel_list_t panels = mPanels; // copy list of panel pointers
  183. mPanels.clear(); // clear so that removeChild() calls don't cause trouble
  184. std::for_each(panels.begin(), panels.end(), DeletePointer());
  185. }
  186. void LLLayoutStack::draw()
  187. {
  188. updateLayout();
  189. // always clip to stack itself
  190. LLLocalClipRect clip(getLocalRect());
  191. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  192. {
  193. // clip to layout rectangle, not bounding rectangle
  194. LLRect clip_rect = panelp->getRect();
  195. // scale clipping rectangle by visible amount
  196. if (mOrientation == HORIZONTAL)
  197. {
  198. clip_rect.mRight = clip_rect.mLeft + panelp->getVisibleDim();
  199. }
  200. else
  201. {
  202. clip_rect.mBottom = clip_rect.mTop - panelp->getVisibleDim();
  203. }
  204. {LLLocalClipRect clip(clip_rect, mClip);
  205. // only force drawing invisible children if visible amount is non-zero
  206. drawChild(panelp, 0, 0, !clip_rect.isEmpty());
  207. }
  208. }
  209. mAnimatedThisFrame = false;
  210. }
  211. void LLLayoutStack::removeChild(LLView* view)
  212. {
  213. LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
  214. if (embedded_panelp)
  215. {
  216. mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
  217. delete embedded_panelp;
  218. updateFractionalSizes();
  219. mNeedsLayout = true;
  220. }
  221. LLView::removeChild(view);
  222. }
  223. BOOL LLLayoutStack::postBuild()
  224. {
  225. updateLayout();
  226. return TRUE;
  227. }
  228. bool LLLayoutStack::addChild(LLView* child, S32 tab_group)
  229. {
  230. LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child);
  231. if (panelp)
  232. {
  233. panelp->setOrientation(mOrientation);
  234. mPanels.push_back(panelp);
  235. createResizeBar(panelp);
  236. mNeedsLayout = true;
  237. }
  238. BOOL result = LLView::addChild(child, tab_group);
  239. updateFractionalSizes();
  240. return result;
  241. }
  242. void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate)
  243. {
  244. addChild(panel);
  245. // panel starts off invisible (collapsed)
  246. if (animate == ANIMATE)
  247. {
  248. panel->mVisibleAmt = 0.f;
  249. panel->setVisible(TRUE);
  250. }
  251. }
  252. void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
  253. {
  254. LLLayoutPanel* panel_container = findEmbeddedPanel(panel);
  255. if (!panel_container) return;
  256. panel_container->mCollapsed = collapsed;
  257. mNeedsLayout = true;
  258. }
  259. static LLFastTimer::DeclareTimer FTM_UPDATE_LAYOUT("Update LayoutStacks");
  260. void LLLayoutStack::updateLayout()
  261. {
  262. LLFastTimer ft(FTM_UPDATE_LAYOUT);
  263. if (!mNeedsLayout) return;
  264. bool animation_in_progress = animatePanels();
  265. F32 total_visible_fraction = 0.f;
  266. F32 total_open_fraction = 0.f;
  267. S32 space_to_distribute = (mOrientation == HORIZONTAL)
  268. ? getRect().getWidth()
  269. : getRect().getHeight();
  270. // first, assign minimum dimensions
  271. LLLayoutPanel* panelp = NULL;
  272. BOOST_FOREACH(panelp, mPanels)
  273. {
  274. if (panelp->mAutoResize)
  275. {
  276. panelp->mTargetDim = panelp->getRelevantMinDim();
  277. if (!panelp->mCollapsed && panelp->getVisible())
  278. {
  279. total_open_fraction += panelp->mFractionalSize;
  280. }
  281. }
  282. space_to_distribute -= panelp->getVisibleDim() + llround((F32)mPanelSpacing * panelp->getVisibleAmount());
  283. total_visible_fraction += panelp->mFractionalSize;
  284. }
  285. llassert(total_visible_fraction < 1.01f);
  286. // don't need spacing after last panel
  287. space_to_distribute += panelp ? llround((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0;
  288. F32 fraction_distributed = 0.f;
  289. if (space_to_distribute > 0 && total_visible_fraction > 0.f)
  290. { // give space proportionally to visible auto resize panels
  291. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  292. {
  293. if (panelp->mAutoResize)
  294. {
  295. F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction);
  296. S32 delta = llround((F32)space_to_distribute * fraction_to_distribute);
  297. fraction_distributed += fraction_to_distribute;
  298. panelp->mTargetDim += delta;
  299. }
  300. }
  301. }
  302. if (fraction_distributed < total_visible_fraction)
  303. { // distribute any left over pixels to non-collapsed, visible panels
  304. F32 fraction_left = total_visible_fraction - fraction_distributed;
  305. S32 space_left = llround((F32)space_to_distribute * (fraction_left / total_visible_fraction));
  306. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  307. {
  308. if (panelp->mAutoResize
  309. && !panelp->mCollapsed
  310. && panelp->getVisible())
  311. {
  312. S32 space_for_panel = llmax(0, llround((F32)space_left * (panelp->mFractionalSize / total_open_fraction)));
  313. panelp->mTargetDim += space_for_panel;
  314. space_left -= space_for_panel;
  315. total_open_fraction -= panelp->mFractionalSize;
  316. }
  317. }
  318. }
  319. F32 cur_pos = (mOrientation == HORIZONTAL) ? 0.f : (F32)getRect().getHeight();
  320. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  321. {
  322. F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim);
  323. F32 panel_visible_dim = panelp->getVisibleDim();
  324. LLRect panel_rect;
  325. if (mOrientation == HORIZONTAL)
  326. {
  327. panel_rect.setLeftTopAndSize(llround(cur_pos),
  328. getRect().getHeight(),
  329. llround(panel_dim),
  330. getRect().getHeight());
  331. }
  332. else
  333. {
  334. panel_rect.setLeftTopAndSize(0,
  335. llround(cur_pos),
  336. getRect().getWidth(),
  337. llround(panel_dim));
  338. }
  339. panelp->setIgnoreReshape(true);
  340. panelp->setShape(panel_rect);
  341. panelp->setIgnoreReshape(false);
  342. LLRect resize_bar_rect(panel_rect);
  343. F32 panel_spacing = (F32)mPanelSpacing * panelp->getVisibleAmount();
  344. if (mOrientation == HORIZONTAL)
  345. {
  346. resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap;
  347. resize_bar_rect.mRight = panel_rect.mRight + (S32)(llround(panel_spacing)) + mResizeBarOverlap;
  348. cur_pos += panel_visible_dim + panel_spacing;
  349. }
  350. else //VERTICAL
  351. {
  352. resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap;
  353. resize_bar_rect.mBottom = panel_rect.mBottom - (S32)(llround(panel_spacing)) - mResizeBarOverlap;
  354. cur_pos -= panel_visible_dim + panel_spacing;
  355. }
  356. panelp->mResizeBar->setShape(resize_bar_rect);
  357. }
  358. updateResizeBarLimits();
  359. // clear animation flag at end, since panel resizes will set it
  360. // and leave it set if there is any animation in progress
  361. mNeedsLayout = animation_in_progress;
  362. } // end LLLayoutStack::updateLayout
  363. LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
  364. {
  365. if (!panelp) return NULL;
  366. e_panel_list_t::const_iterator panel_it;
  367. BOOST_FOREACH(LLLayoutPanel* p, mPanels)
  368. {
  369. if (p == panelp)
  370. {
  371. return p;
  372. }
  373. }
  374. return NULL;
  375. }
  376. LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const
  377. {
  378. LLLayoutPanel* result = NULL;
  379. BOOST_FOREACH(LLLayoutPanel* p, mPanels)
  380. {
  381. if (p->getName() == name)
  382. {
  383. result = p;
  384. break;
  385. }
  386. }
  387. return result;
  388. }
  389. void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)
  390. {
  391. BOOST_FOREACH(LLLayoutPanel* lp, mPanels)
  392. {
  393. if (lp->mResizeBar == NULL)
  394. {
  395. LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
  396. LLRect resize_bar_rect = getRect();
  397. LLResizeBar::Params resize_params;
  398. resize_params.name("resize");
  399. resize_params.resizing_view(lp);
  400. resize_params.min_size(lp->getRelevantMinDim());
  401. resize_params.side(side);
  402. resize_params.snapping_enabled(false);
  403. LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params);
  404. lp->mResizeBar = resize_bar;
  405. LLView::addChild(resize_bar, 0);
  406. }
  407. }
  408. // bring all resize bars to the front so that they are clickable even over the panels
  409. // with a bit of overlap
  410. for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  411. {
  412. LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
  413. sendChildToFront(resize_barp);
  414. }
  415. }
  416. // update layout stack animations, etc. once per frame
  417. // NOTE: we use this to size world view based on animating UI, *before* we draw the UI
  418. // we might still need to call updateLayout during UI draw phase, in case UI elements
  419. // are resizing themselves dynamically
  420. //static
  421. void LLLayoutStack::updateClass()
  422. {
  423. for (instance_iter it = beginInstances(); it != endInstances(); ++it)
  424. {
  425. it->updateLayout();
  426. }
  427. }
  428. void LLLayoutStack::updateFractionalSizes()
  429. {
  430. F32 total_resizable_dim = 0;
  431. S32 num_auto_resize_panels = 0;
  432. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  433. {
  434. if (panelp->mAutoResize)
  435. {
  436. total_resizable_dim += llmax(0, panelp->getLayoutDim() - panelp->getRelevantMinDim());
  437. num_auto_resize_panels++;
  438. }
  439. }
  440. F32 total_fractional_size = 0.f;
  441. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  442. {
  443. if (panelp->mAutoResize)
  444. {
  445. F32 panel_resizable_dim = llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim()));
  446. panelp->mFractionalSize = panel_resizable_dim > 0.f
  447. ? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE)
  448. : MIN_FRACTIONAL_SIZE;
  449. total_fractional_size += panelp->mFractionalSize;
  450. llassert(!llisnan(panelp->mFractionalSize));
  451. }
  452. }
  453. if (total_fractional_size == 0.f)
  454. { // equal distribution
  455. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  456. {
  457. if (panelp->mAutoResize)
  458. {
  459. panelp->mFractionalSize = MAX_FRACTIONAL_SIZE / (F32)num_auto_resize_panels;
  460. }
  461. }
  462. }
  463. else
  464. { // renormalize
  465. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  466. {
  467. if (panelp->mAutoResize)
  468. {
  469. panelp->mFractionalSize /= total_fractional_size;
  470. }
  471. }
  472. }
  473. }
  474. bool LLLayoutStack::animatePanels()
  475. {
  476. bool animation_in_progress = false;
  477. //
  478. // animate visibility
  479. //
  480. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  481. {
  482. if (panelp->getVisible())
  483. {
  484. if (mAnimate && panelp->mVisibleAmt < 1.f)
  485. {
  486. if (!mAnimatedThisFrame)
  487. {
  488. panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(mOpenTimeConstant));
  489. if (panelp->mVisibleAmt > 0.99f)
  490. {
  491. panelp->mVisibleAmt = 1.f;
  492. }
  493. }
  494. animation_in_progress = true;
  495. }
  496. else
  497. {
  498. if (panelp->mVisibleAmt != 1.f)
  499. {
  500. panelp->mVisibleAmt = 1.f;
  501. animation_in_progress = true;
  502. }
  503. }
  504. }
  505. else // not visible
  506. {
  507. if (mAnimate && panelp->mVisibleAmt > 0.f)
  508. {
  509. if (!mAnimatedThisFrame)
  510. {
  511. panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
  512. if (panelp->mVisibleAmt < 0.001f)
  513. {
  514. panelp->mVisibleAmt = 0.f;
  515. }
  516. }
  517. animation_in_progress = true;
  518. }
  519. else
  520. {
  521. if (panelp->mVisibleAmt != 0.f)
  522. {
  523. panelp->mVisibleAmt = 0.f;
  524. animation_in_progress = true;
  525. }
  526. }
  527. }
  528. F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f;
  529. if (panelp->mCollapseAmt != collapse_state)
  530. {
  531. if (!mAnimatedThisFrame)
  532. {
  533. panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
  534. }
  535. animation_in_progress = true;
  536. if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f)
  537. {
  538. panelp->mCollapseAmt = collapse_state;
  539. }
  540. }
  541. }
  542. mAnimatedThisFrame = true;
  543. return animation_in_progress;
  544. }
  545. void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& new_rect )
  546. {
  547. S32 new_dim = (mOrientation == HORIZONTAL)
  548. ? new_rect.getWidth()
  549. : new_rect.getHeight();
  550. S32 delta_dim = new_dim - resized_panel->getVisibleDim();
  551. if (delta_dim == 0) return;
  552. F32 total_visible_fraction = 0.f;
  553. F32 delta_auto_resize_headroom = 0.f;
  554. F32 total_auto_resize_headroom = 0.f;
  555. LLLayoutPanel* other_resize_panel = NULL;
  556. LLLayoutPanel* following_panel = NULL;
  557. BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels)
  558. {
  559. if (panelp->mAutoResize)
  560. {
  561. total_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim());
  562. total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor();
  563. }
  564. if (panelp == resized_panel)
  565. {
  566. other_resize_panel = following_panel;
  567. }
  568. if (panelp->getVisible() && !panelp->mCollapsed)
  569. {
  570. following_panel = panelp;
  571. }
  572. }
  573. if (resized_panel->mAutoResize == FALSE)
  574. {
  575. delta_auto_resize_headroom += -delta_dim;
  576. }
  577. if (other_resize_panel && other_resize_panel->mAutoResize == FALSE)
  578. {
  579. delta_auto_resize_headroom += delta_dim;
  580. }
  581. F32 fraction_given_up = 0.f;
  582. F32 fraction_remaining = 1.f;
  583. F32 updated_auto_resize_headroom = total_auto_resize_headroom + delta_auto_resize_headroom;
  584. enum
  585. {
  586. BEFORE_RESIZED_PANEL,
  587. RESIZED_PANEL,
  588. NEXT_PANEL,
  589. AFTER_RESIZED_PANEL
  590. } which_panel = BEFORE_RESIZED_PANEL;
  591. BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
  592. {
  593. if (!panelp->getVisible() || panelp->mCollapsed) continue;
  594. if (panelp == resized_panel)
  595. {
  596. which_panel = RESIZED_PANEL;
  597. }
  598. switch(which_panel)
  599. {
  600. case BEFORE_RESIZED_PANEL:
  601. if (panelp->mAutoResize)
  602. { // freeze current size as fraction of overall auto_resize space
  603. F32 fractional_adjustment_factor = total_auto_resize_headroom / updated_auto_resize_headroom;
  604. F32 new_fractional_size = llclamp(panelp->mFractionalSize * fractional_adjustment_factor,
  605. MIN_FRACTIONAL_SIZE,
  606. MAX_FRACTIONAL_SIZE);
  607. F32 fraction_delta = (new_fractional_size - panelp->mFractionalSize);
  608. fraction_given_up -= fraction_delta;
  609. fraction_remaining -= panelp->mFractionalSize;
  610. panelp->mFractionalSize += fraction_delta;
  611. llassert(!llisnan(panelp->mFractionalSize));
  612. }
  613. else
  614. {
  615. // leave non auto-resize panels alone
  616. }
  617. break;
  618. case RESIZED_PANEL:
  619. if (panelp->mAutoResize)
  620. { // freeze new size as fraction
  621. F32 new_fractional_size = (updated_auto_resize_headroom == 0.f)
  622. ? MAX_FRACTIONAL_SIZE
  623. : llclamp((F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);
  624. fraction_given_up -= new_fractional_size - panelp->mFractionalSize;
  625. fraction_remaining -= panelp->mFractionalSize;
  626. panelp->mFractionalSize = new_fractional_size;
  627. llassert(!llisnan(panelp->mFractionalSize));
  628. }
  629. else
  630. { // freeze new size as original size
  631. panelp->mTargetDim = new_dim;
  632. fraction_remaining -= fraction_given_up;
  633. }
  634. which_panel = NEXT_PANEL;
  635. break;
  636. case NEXT_PANEL:
  637. if (panelp->mAutoResize)
  638. {
  639. fraction_remaining -= panelp->mFractionalSize;
  640. if (fraction_given_up != 0.f)
  641. {
  642. panelp->mFractionalSize = llclamp(panelp->mFractionalSize + fraction_given_up, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);
  643. fraction_given_up = 0.f;
  644. }
  645. else
  646. {
  647. F32 new_fractional_size = llclamp((F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom)
  648. / updated_auto_resize_headroom,
  649. MIN_FRACTIONAL_SIZE,
  650. MAX_FRACTIONAL_SIZE);
  651. fraction_given_up -= new_fractional_size - panelp->mFractionalSize;
  652. panelp->mFractionalSize = new_fractional_size;
  653. }
  654. }
  655. else
  656. {
  657. panelp->mTargetDim -= delta_dim;
  658. }
  659. which_panel = AFTER_RESIZED_PANEL;
  660. break;
  661. case AFTER_RESIZED_PANEL:
  662. if (panelp->mAutoResize)
  663. {
  664. panelp->mFractionalSize = llclamp(panelp->mFractionalSize + (panelp->mFractionalSize / fraction_remaining) * fraction_given_up,
  665. MIN_FRACTIONAL_SIZE,
  666. MAX_FRACTIONAL_SIZE);
  667. }
  668. default:
  669. break;
  670. }
  671. }
  672. }
  673. void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent)
  674. {
  675. mNeedsLayout = true;
  676. LLView::reshape(width, height, called_from_parent);
  677. }
  678. void LLLayoutStack::updateResizeBarLimits()
  679. {
  680. LLLayoutPanel* previous_visible_panelp = NULL;
  681. BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels)
  682. {
  683. if (!visible_panelp->getVisible() || visible_panelp->mCollapsed)
  684. {
  685. visible_panelp->mResizeBar->setVisible(FALSE);
  686. continue;
  687. }
  688. // toggle resize bars based on panel visibility, resizability, etc
  689. if (previous_visible_panelp
  690. && (visible_panelp->mUserResize || previous_visible_panelp->mUserResize) // one of the pair is user resizable
  691. && (visible_panelp->mAutoResize || visible_panelp->mUserResize) // current panel is resizable
  692. && (previous_visible_panelp->mAutoResize || previous_visible_panelp->mUserResize)) // previous panel is resizable
  693. {
  694. visible_panelp->mResizeBar->setVisible(TRUE);
  695. S32 previous_panel_headroom = previous_visible_panelp->getVisibleDim() - previous_visible_panelp->getRelevantMinDim();
  696. visible_panelp->mResizeBar->setResizeLimits(visible_panelp->getRelevantMinDim(),
  697. visible_panelp->getVisibleDim() + previous_panel_headroom);
  698. }
  699. else
  700. {
  701. visible_panelp->mResizeBar->setVisible(FALSE);
  702. }
  703. previous_visible_panelp = visible_panelp;
  704. }
  705. }