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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lllayoutstack.cpp
  3.  * @brief LLLayout class - dynamic stacking of UI elements
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. // Opaque view with a background and a border.  Can contain LLUICtrls.
  33. #include "linden_common.h"
  34. #include "lllayoutstack.h"
  35. #include "lllocalcliprect.h"
  36. #include "llpanel.h"
  37. #include "llresizebar.h"
  38. #include "llcriticaldamp.h"
  39. static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack", &LLLayoutStack::fromXML);
  40. //
  41. // LLLayoutStack
  42. //
  43. struct LLLayoutStack::LayoutPanel
  44. {
  45. LayoutPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) : mPanel(panelp), 
  46. mMinWidth(min_width), 
  47. mMinHeight(min_height),
  48. mAutoResize(auto_resize),
  49. mUserResize(user_resize),
  50. mOrientation(orientation),
  51. mCollapsed(FALSE),
  52. mCollapseAmt(0.f),
  53. mVisibleAmt(1.f), // default to fully visible
  54. mResizeBar(NULL) 
  55. {
  56. LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
  57. LLRect resize_bar_rect = panelp->getRect();
  58. S32 min_dim;
  59. if (orientation == HORIZONTAL)
  60. {
  61. min_dim = mMinHeight;
  62. }
  63. else
  64. {
  65. min_dim = mMinWidth;
  66. }
  67. LLResizeBar::Params p;
  68. p.name("resize");
  69. p.resizing_view(mPanel);
  70. p.min_size(min_dim);
  71. p.side(side);
  72. p.snapping_enabled(false);
  73. mResizeBar = LLUICtrlFactory::create<LLResizeBar>(p);
  74. // panels initialized as hidden should not start out partially visible
  75. if (!mPanel->getVisible())
  76. {
  77. mVisibleAmt = 0.f;
  78. }
  79. }
  80. ~LayoutPanel()
  81. {
  82. // probably not necessary, but...
  83. delete mResizeBar;
  84. mResizeBar = NULL;
  85. }
  86. F32 getCollapseFactor()
  87. {
  88. if (mOrientation == HORIZONTAL)
  89. {
  90. F32 collapse_amt = 
  91. clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth()));
  92. return mVisibleAmt * collapse_amt;
  93. }
  94. else
  95. {
  96. F32 collapse_amt = 
  97. clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight())));
  98. return mVisibleAmt * collapse_amt;
  99. }
  100. }
  101. LLPanel* mPanel;
  102. S32 mMinWidth;
  103. S32 mMinHeight;
  104. BOOL mAutoResize;
  105. BOOL mUserResize;
  106. BOOL mCollapsed;
  107. LLResizeBar* mResizeBar;
  108. ELayoutOrientation mOrientation;
  109. F32 mVisibleAmt;
  110. F32 mCollapseAmt;
  111. };
  112. LLLayoutStack::Params::Params()
  113. : orientation("orientation", std::string("vertical")),
  114. animate("animate", true),
  115. clip("clip", true),
  116. border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))
  117. {
  118. name="stack";
  119. }
  120. LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) 
  121. : LLView(p),
  122. mMinWidth(0),
  123. mMinHeight(0),
  124. mPanelSpacing(p.border_size),
  125. mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),
  126. mAnimate(p.animate),
  127. mAnimatedThisFrame(false),
  128. mClip(p.clip)
  129. {}
  130. LLLayoutStack::~LLLayoutStack()
  131. {
  132. e_panel_list_t panels = mPanels; // copy list of panel pointers
  133. mPanels.clear(); // clear so that removeChild() calls don't cause trouble
  134. std::for_each(panels.begin(), panels.end(), DeletePointer());
  135. }
  136. void LLLayoutStack::draw()
  137. {
  138. updateLayout();
  139. e_panel_list_t::iterator panel_it;
  140. for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  141. {
  142. // clip to layout rectangle, not bounding rectangle
  143. LLRect clip_rect = (*panel_it)->mPanel->getRect();
  144. // scale clipping rectangle by visible amount
  145. if (mOrientation == HORIZONTAL)
  146. {
  147. clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
  148. }
  149. else
  150. {
  151. clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
  152. }
  153. LLPanel* panelp = (*panel_it)->mPanel;
  154. LLLocalClipRect clip(clip_rect, mClip);
  155. // only force drawing invisible children if visible amount is non-zero
  156. drawChild(panelp, 0, 0, !clip_rect.isEmpty());
  157. }
  158. mAnimatedThisFrame = false;
  159. }
  160. void LLLayoutStack::removeChild(LLView* view)
  161. {
  162. LayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
  163. if (embedded_panelp)
  164. {
  165. mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
  166. delete embedded_panelp;
  167. }
  168. // need to update resizebars
  169. calcMinExtents();
  170. LLView::removeChild(view);
  171. }
  172. BOOL LLLayoutStack::postBuild()
  173. {
  174. updateLayout();
  175. return TRUE;
  176. }
  177. static void get_attribute_s32_and_write(LLXMLNodePtr node,
  178. const char* name,
  179. S32 *value,
  180. S32 default_value,
  181. LLXMLNodePtr output_child)
  182. {
  183. BOOL has_attr = node->getAttributeS32(name, *value);
  184. if (has_attr && *value != default_value && output_child)
  185. {
  186. // create an attribute child node
  187. LLXMLNodePtr child_attr = output_child->createChild(name, TRUE);
  188. child_attr->setIntValue(*value);
  189. }
  190. }
  191. static void get_attribute_bool_and_write(LLXMLNodePtr node,
  192. const char* name,
  193. BOOL *value,
  194. BOOL default_value,
  195. LLXMLNodePtr output_child)
  196. {
  197. BOOL has_attr = node->getAttributeBOOL(name, *value);
  198. if (has_attr && *value != default_value && output_child)
  199. {
  200. LLXMLNodePtr child_attr = output_child->createChild(name, TRUE);
  201. child_attr->setBoolValue(*value);
  202. }
  203. }
  204. //static 
  205. LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
  206. {
  207. LLLayoutStack::Params p(LLUICtrlFactory::getDefaultParams<LLLayoutStack>());
  208. LLXUIParser::instance().readXUI(node, p, LLUICtrlFactory::getInstance()->getCurFileName());
  209. // Export must happen before setupParams() mungles rectangles and before
  210. // this item gets added to parent (otherwise screws up last_child_rect
  211. // logic). JC
  212. if (output_node)
  213. {
  214. Params output_params(p);
  215. setupParamsForExport(output_params, parent);
  216. LLLayoutStack::Params default_params(LLUICtrlFactory::getDefaultParams<LLLayoutStack>());
  217. output_node->setName(node->getName()->mString);
  218. LLXUIParser::instance().writeXUI(
  219. output_node, output_params, &default_params);
  220. }
  221. p.from_xui = true;
  222. applyXUILayout(p, parent);
  223. LLLayoutStack* layout_stackp = LLUICtrlFactory::create<LLLayoutStack>(p);
  224. if (parent && layout_stackp)
  225. {
  226. S32 tab_group = p.tab_group.isProvided() ? p.tab_group() : parent->getLastTabGroup();
  227. parent->addChild(layout_stackp, tab_group);
  228. }
  229. for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
  230. {
  231. const S32 DEFAULT_MIN_WIDTH = 0;
  232. const S32 DEFAULT_MIN_HEIGHT = 0;
  233. const BOOL DEFAULT_AUTO_RESIZE = TRUE;
  234. S32 min_width = DEFAULT_MIN_WIDTH;
  235. S32 min_height = DEFAULT_MIN_HEIGHT;
  236. BOOL auto_resize = DEFAULT_AUTO_RESIZE;
  237. LLXMLNodePtr output_child;
  238. if (output_node) 
  239. {
  240. output_child = output_node->createChild("", FALSE);
  241. }
  242. // Layout stack allows child nodes to acquire additional attributes,
  243. // such as "min_width" in:  <button label="Foo" min_width="100"/>
  244. // If these attributes exist and have non-default values, write them
  245. // to the output node.
  246. get_attribute_s32_and_write(child_node, "min_width", &min_width,
  247. DEFAULT_MIN_WIDTH, output_child);
  248. get_attribute_s32_and_write(child_node, "min_height", &min_height,
  249. DEFAULT_MIN_HEIGHT, output_child);
  250. get_attribute_bool_and_write(child_node, "auto_resize", &auto_resize,
  251. DEFAULT_AUTO_RESIZE, output_child);
  252. if (child_node->hasName("layout_panel"))
  253. {
  254. BOOL user_resize = TRUE;
  255. get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
  256. TRUE, output_child);
  257. LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child_node, layout_stackp, output_child);
  258. if (panelp)
  259. {
  260. panelp->setFollowsNone();
  261. layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
  262. }
  263. }
  264. else
  265. {
  266. BOOL user_resize = FALSE;
  267. get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
  268. FALSE, output_child);
  269. LLPanel::Params p;
  270. p.mouse_opaque(false);
  271. LLPanel* panelp = LLUICtrlFactory::create<LLPanel>(p);
  272. LLView* new_child = LLUICtrlFactory::getInstance()->createFromXML(child_node, panelp, LLStringUtil::null, LLPanel::child_registry_t::instance(), output_child);
  273. if (new_child)
  274. {
  275. // put child in new embedded panel
  276. layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
  277. // resize panel to contain widget and move widget to be contained in panel
  278. panelp->setRect(new_child->getRect());
  279. new_child->setOrigin(0, 0);
  280. }
  281. else
  282. {
  283. panelp->die();
  284. }
  285. }
  286. if (output_child && !output_child->mChildren && output_child->mAttributes.empty() && output_child->getValue().empty())
  287. {
  288. output_node->deleteChild(output_child);
  289. }
  290. }
  291. if (!layout_stackp->postBuild())
  292. {
  293. delete layout_stackp;
  294. return NULL;
  295. }
  296. return layout_stackp;
  297. }
  298. S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
  299. {
  300. // if we are spanning our children (crude upward propagation of size)
  301. // then don't enforce our size on our children
  302. if (mOrientation == HORIZONTAL)
  303. {
  304. cur_height = llmax(mMinHeight, getRect().getHeight());
  305. }
  306. return cur_height;
  307. }
  308. S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
  309. {
  310. // if we are spanning our children (crude upward propagation of size)
  311. // then don't enforce our size on our children
  312. if (mOrientation == VERTICAL)
  313. {
  314. cur_width = llmax(mMinWidth, getRect().getWidth());
  315. }
  316. return cur_width;
  317. }
  318. void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index)
  319. {
  320. // panel starts off invisible (collapsed)
  321. if (animate == ANIMATE)
  322. {
  323. panel->setVisible(FALSE);
  324. }
  325. LayoutPanel* embedded_panel = new LayoutPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
  326. mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
  327. if (panel->getParent() != this) 
  328. {
  329. addChild(panel);
  330. }
  331. addChild(embedded_panel->mResizeBar);
  332. // bring all resize bars to the front so that they are clickable even over the panels
  333. // with a bit of overlap
  334. for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  335. {
  336. LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
  337. sendChildToFront(resize_barp);
  338. }
  339. // start expanding panel animation
  340. if (animate == ANIMATE)
  341. {
  342. panel->setVisible(TRUE);
  343. }
  344. }
  345. void LLLayoutStack::removePanel(LLPanel* panel)
  346. {
  347. removeChild(panel);
  348. }
  349. void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
  350. {
  351. LayoutPanel* panel_container = findEmbeddedPanel(panel);
  352. if (!panel_container) return;
  353. panel_container->mCollapsed = collapsed;
  354. }
  355. void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize)
  356. {
  357. LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
  358. if (panel)
  359. {
  360. panel->mAutoResize = auto_resize;
  361. }
  362. }
  363. void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_resize)
  364. {
  365. LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
  366. if (panel)
  367. {
  368. panel->mUserResize = user_resize;
  369. }
  370. }
  371. bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_widthp, S32* min_heightp)
  372. {
  373. LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
  374. if (panel)
  375. {
  376. if (min_widthp) *min_widthp = panel->mMinWidth;
  377. if (min_heightp) *min_heightp = panel->mMinHeight;
  378. }
  379. return NULL != panel;
  380. }
  381. static LLFastTimer::DeclareTimer FTM_UPDATE_LAYOUT("Update LayoutStacks");
  382. void LLLayoutStack::updateLayout(BOOL force_resize)
  383. {
  384. LLFastTimer ft(FTM_UPDATE_LAYOUT);
  385. static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0);
  386. calcMinExtents();
  387. // calculate current extents
  388. S32 total_width = 0;
  389. S32 total_height = 0;
  390. const F32 ANIM_OPEN_TIME = 0.02f;
  391. const F32 ANIM_CLOSE_TIME = 0.03f;
  392. e_panel_list_t::iterator panel_it;
  393. for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  394. {
  395. LLPanel* panelp = (*panel_it)->mPanel;
  396. if (panelp->getVisible()) 
  397. {
  398. if (mAnimate)
  399. {
  400. if (!mAnimatedThisFrame)
  401. {
  402. (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
  403. if ((*panel_it)->mVisibleAmt > 0.99f)
  404. {
  405. (*panel_it)->mVisibleAmt = 1.f;
  406. }
  407. }
  408. }
  409. else
  410. {
  411. (*panel_it)->mVisibleAmt = 1.f;
  412. }
  413. }
  414. else // not visible
  415. {
  416. if (mAnimate)
  417. {
  418. if (!mAnimatedThisFrame)
  419. {
  420. (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
  421. if ((*panel_it)->mVisibleAmt < 0.001f)
  422. {
  423. (*panel_it)->mVisibleAmt = 0.f;
  424. }
  425. }
  426. }
  427. else
  428. {
  429. (*panel_it)->mVisibleAmt = 0.f;
  430. }
  431. }
  432. if ((*panel_it)->mCollapsed)
  433. {
  434. (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
  435. }
  436. else
  437. {
  438. (*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
  439. }
  440. if (mOrientation == HORIZONTAL)
  441. {
  442. // enforce minimize size constraint by default
  443. if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth)
  444. {
  445. panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
  446. }
  447.          total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor());
  448.          // want n-1 panel gaps for n panels
  449. if (panel_it != mPanels.begin())
  450. {
  451. total_width += mPanelSpacing;
  452. }
  453. }
  454. else //VERTICAL
  455. {
  456. // enforce minimize size constraint by default
  457. if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight)
  458. {
  459. panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
  460. }
  461. total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor());
  462. if (panel_it != mPanels.begin())
  463. {
  464. total_height += mPanelSpacing;
  465. }
  466. }
  467. }
  468. S32 num_resizable_panels = 0;
  469. S32 shrink_headroom_available = 0;
  470. S32 shrink_headroom_total = 0;
  471. for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  472. {
  473. // panels that are not fully visible do not count towards shrink headroom
  474. if ((*panel_it)->getCollapseFactor() < 1.f) 
  475. {
  476. continue;
  477. }
  478. // if currently resizing a panel or the panel is flagged as not automatically resizing
  479. // only track total available headroom, but don't use it for automatic resize logic
  480. if ((*panel_it)->mResizeBar->hasMouseCapture() 
  481. || (!(*panel_it)->mAutoResize 
  482. && !force_resize))
  483. {
  484. if (mOrientation == HORIZONTAL)
  485. {
  486. shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
  487. }
  488. else //VERTICAL
  489. {
  490. shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
  491. }
  492. }
  493. else
  494. {
  495. num_resizable_panels++;
  496. if (mOrientation == HORIZONTAL)
  497. {
  498. shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
  499. shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
  500. }
  501. else //VERTICAL
  502. {
  503. shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
  504. shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
  505. }
  506. }
  507. }
  508. // calculate how many pixels need to be distributed among layout panels
  509. // positive means panels need to grow, negative means shrink
  510. S32 pixels_to_distribute;
  511. if (mOrientation == HORIZONTAL)
  512. {
  513. pixels_to_distribute = getRect().getWidth() - total_width;
  514. }
  515. else //VERTICAL
  516. {
  517. pixels_to_distribute = getRect().getHeight() - total_height;
  518. }
  519. // now we distribute the pixels...
  520. S32 cur_x = 0;
  521. S32 cur_y = getRect().getHeight();
  522. for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  523. {
  524. LLPanel* panelp = (*panel_it)->mPanel;
  525. S32 cur_width = panelp->getRect().getWidth();
  526. S32 cur_height = panelp->getRect().getHeight();
  527. S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
  528. S32 new_height = llmax((*panel_it)->mMinHeight, cur_height); 
  529. S32 delta_size = 0;
  530. // if panel can automatically resize (not animating, and resize flag set)...
  531. if ((*panel_it)->getCollapseFactor() == 1.f 
  532. && (force_resize || (*panel_it)->mAutoResize) 
  533. && !(*panel_it)->mResizeBar->hasMouseCapture()) 
  534. {
  535. if (mOrientation == HORIZONTAL)
  536. {
  537. // if we're shrinking
  538. if (pixels_to_distribute < 0)
  539. {
  540. // shrink proportionally to amount over minimum
  541. // so we can do this in one pass
  542. delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0;
  543. shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth);
  544. }
  545. else
  546. {
  547. // grow all elements equally
  548. delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
  549. num_resizable_panels--;
  550. }
  551. pixels_to_distribute -= delta_size;
  552. new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
  553. }
  554. else
  555. {
  556. new_width = getDefaultWidth(new_width);
  557. }
  558. if (mOrientation == VERTICAL)
  559. {
  560. if (pixels_to_distribute < 0)
  561. {
  562. // shrink proportionally to amount over minimum
  563. // so we can do this in one pass
  564. delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0;
  565. shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight);
  566. }
  567. else
  568. {
  569. delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
  570. num_resizable_panels--;
  571. }
  572. pixels_to_distribute -= delta_size;
  573. new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
  574. }
  575. else
  576. {
  577. new_height = getDefaultHeight(new_height);
  578. }
  579. }
  580. else
  581. {
  582. if (mOrientation == HORIZONTAL)
  583. {
  584. new_height = getDefaultHeight(new_height);
  585. }
  586. else // VERTICAL
  587. {
  588. new_width = getDefaultWidth(new_width);
  589. }
  590. }
  591. // adjust running headroom count based on new sizes
  592. shrink_headroom_total += delta_size;
  593. LLRect panel_rect;
  594. panel_rect.setLeftTopAndSize(cur_x, cur_y, new_width, new_height);
  595. panelp->setShape(panel_rect);
  596. LLRect resize_bar_rect = panel_rect;
  597. if (mOrientation == HORIZONTAL)
  598. {
  599. resize_bar_rect.mLeft = panel_rect.mRight - resize_bar_overlap;
  600. resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + resize_bar_overlap;
  601. }
  602. else
  603. {
  604. resize_bar_rect.mTop = panel_rect.mBottom + resize_bar_overlap;
  605. resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - resize_bar_overlap;
  606. }
  607. (*panel_it)->mResizeBar->setRect(resize_bar_rect);
  608. if (mOrientation == HORIZONTAL)
  609. {
  610. cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
  611. }
  612. else //VERTICAL
  613. {
  614. cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
  615. }
  616. }
  617. // update resize bars with new limits
  618. LLResizeBar* last_resize_bar = NULL;
  619. for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  620. {
  621. LLPanel* panelp = (*panel_it)->mPanel;
  622. if (mOrientation == HORIZONTAL)
  623. {
  624. (*panel_it)->mResizeBar->setResizeLimits(
  625. (*panel_it)->mMinWidth, 
  626. (*panel_it)->mMinWidth + shrink_headroom_total);
  627. }
  628. else //VERTICAL
  629. {
  630. (*panel_it)->mResizeBar->setResizeLimits(
  631. (*panel_it)->mMinHeight, 
  632. (*panel_it)->mMinHeight + shrink_headroom_total);
  633. }
  634. // toggle resize bars based on panel visibility, resizability, etc
  635. BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
  636. (*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
  637. if (resize_bar_enabled)
  638. {
  639. last_resize_bar = (*panel_it)->mResizeBar;
  640. }
  641. }
  642. // hide last resize bar as there is nothing past it
  643. // resize bars need to be in between two resizable panels
  644. if (last_resize_bar)
  645. {
  646. last_resize_bar->setVisible(FALSE);
  647. }
  648. // not enough room to fit existing contents
  649. if (force_resize == FALSE
  650. // layout did not complete by reaching target position
  651. && ((mOrientation == VERTICAL && cur_y != -mPanelSpacing)
  652. || (mOrientation == HORIZONTAL && cur_x != getRect().getWidth() + mPanelSpacing)))
  653. {
  654. // do another layout pass with all stacked elements contributing
  655. // even those that don't usually resize
  656. llassert_always(force_resize == FALSE);
  657. updateLayout(TRUE);
  658. }
  659.  mAnimatedThisFrame = true;
  660. } // end LLLayoutStack::updateLayout
  661. LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
  662. {
  663. if (!panelp) return NULL;
  664. e_panel_list_t::const_iterator panel_it;
  665. for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  666. {
  667. if ((*panel_it)->mPanel == panelp)
  668. {
  669. return *panel_it;
  670. }
  671. }
  672. return NULL;
  673. }
  674. LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const
  675. {
  676. LayoutPanel* result = NULL;
  677. for (e_panel_list_t::const_iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  678. {
  679. LayoutPanel* p = *panel_it;
  680. if (p->mPanel->getName() == name)
  681. {
  682. result = p;
  683. break;
  684. }
  685. }
  686. return result;
  687. }
  688. // Compute sum of min_width or min_height of children
  689. void LLLayoutStack::calcMinExtents()
  690. {
  691. mMinWidth = 0;
  692. mMinHeight = 0;
  693. e_panel_list_t::iterator panel_it;
  694. for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
  695. {
  696. if (mOrientation == HORIZONTAL)
  697. {
  698. mMinHeight = llmax( mMinHeight, 
  699. (*panel_it)->mMinHeight);
  700.             mMinWidth += (*panel_it)->mMinWidth;
  701. if (panel_it != mPanels.begin())
  702. {
  703. mMinWidth += mPanelSpacing;
  704. }
  705. }
  706. else //VERTICAL
  707. {
  708.         mMinWidth = llmax( mMinWidth, 
  709. (*panel_it)->mMinWidth);
  710. mMinHeight += (*panel_it)->mMinHeight;
  711. if (panel_it != mPanels.begin())
  712. {
  713. mMinHeight += mPanelSpacing;
  714. }
  715. }
  716. }
  717. }
  718. // update layout stack animations, etc. once per frame
  719. // NOTE: we use this to size world view based on animating UI, *before* we draw the UI
  720. // we might still need to call updateLayout during UI draw phase, in case UI elements
  721. // are resizing themselves dynamically
  722. //static 
  723. void LLLayoutStack::updateClass()
  724. {
  725. LLInstanceTrackerScopedGuard guard;
  726. for (LLLayoutStack::instance_iter it = guard.beginInstances();
  727.      it != guard.endInstances();
  728.      ++it)
  729. {
  730. it->updateLayout();
  731. }
  732. }