VirLinden avatar VirLinden committed 34a8395 Merge

merge

Comments (0)

Files changed (133)

doc/contributions.txt

 	STORM-1737
 	STORM-1733
 	STORM-1790
+	STORM-1788
+	STORM-1799
+	STORM-1796
 Kadah Coba
 	STORM-1060
 Jondan Lundquist

indra/llui/lllayoutstack.cpp

 #include "llpanel.h"
 #include "llresizebar.h"
 #include "llcriticaldamp.h"
+#include "boost/foreach.hpp"
+
+static const F32 MIN_FRACTIONAL_SIZE = 0.0001f;
+static const F32 MAX_FRACTIONAL_SIZE = 1.f;
 
 static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");
 static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel");
 //
 LLLayoutPanel::Params::Params()	
 :	expanded_min_dim("expanded_min_dim", 0),
-	min_dim("min_dim", 0),
-	max_dim("max_dim", S32_MAX),
-	user_resize("user_resize", true),
+	min_dim("min_dim", -1),
+	user_resize("user_resize", false),
 	auto_resize("auto_resize", true)
 {
 	addSynonym(min_dim, "min_width");
 	addSynonym(min_dim, "min_height");
-	addSynonym(max_dim, "max_width");
-	addSynonym(max_dim, "max_height");
 }
 
 LLLayoutPanel::LLLayoutPanel(const Params& p)	
 :	LLPanel(p),
-	mExpandedMinDimSpecified(false),
-	mExpandedMinDim(p.min_dim),
+	mExpandedMinDim(p.expanded_min_dim.isProvided() ? p.expanded_min_dim : p.min_dim),
  	mMinDim(p.min_dim), 
- 	mMaxDim(p.max_dim), 
  	mAutoResize(p.auto_resize),
  	mUserResize(p.user_resize),
 	mCollapsed(FALSE),
 	mCollapseAmt(0.f),
 	mVisibleAmt(1.f), // default to fully visible
 	mResizeBar(NULL),
-	mFractionalSize(0.f),
+	mFractionalSize(MIN_FRACTIONAL_SIZE),
+	mTargetDim(0),
+	mIgnoreReshape(false),
 	mOrientation(LLLayoutStack::HORIZONTAL)
 {
-	// Set the expanded min dim if it is provided, otherwise it gets the p.min_dim value
-	if (p.expanded_min_dim.isProvided())
-	{
-		mExpandedMinDimSpecified = true;
-		mExpandedMinDim = p.expanded_min_dim();
-	}
-	
 	// panels initialized as hidden should not start out partially visible
 	if (!getVisible())
 	{
 	mResizeBar = NULL;
 }
 
-void LLLayoutPanel::reshape(S32 width, S32 height, BOOL called_from_parent)
+F32 LLLayoutPanel::getAutoResizeFactor() const
 {
-	if (mOrientation == LLLayoutStack::HORIZONTAL)
+	return mVisibleAmt * (1.f - mCollapseAmt);
+}
+ 
+F32 LLLayoutPanel::getVisibleAmount() const
+{
+	return mVisibleAmt;
+}
+
+S32 LLLayoutPanel::getLayoutDim() const
+{
+	return llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL)
+					? getRect().getWidth()
+					: getRect().getHeight()));
+}
+ 
+S32 LLLayoutPanel::getVisibleDim() const
+{
+	F32 min_dim = getRelevantMinDim();
+	return llround(mVisibleAmt
+					* (min_dim
+						+ (((F32)mTargetDim - min_dim) * (1.f - mCollapseAmt))));
+}
+ 
+void LLLayoutPanel::setOrientation( LLLayoutStack::ELayoutOrientation orientation )
+{
+	mOrientation = orientation;
+	S32 layout_dim = llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL)
+		? getRect().getWidth()
+		: getRect().getHeight()));
+
+	mTargetDim = llmax(layout_dim, getMinDim());
+}
+ 
+void LLLayoutPanel::setVisible( BOOL visible )
+{
+	if (visible != getVisible())
 	{
-		mFractionalSize += width - llround(mFractionalSize);
+		LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent());
+		if (stackp)
+		{
+			stackp->mNeedsLayout = true;
+		}
 	}
-	else
+	LLPanel::setVisible(visible);
+}
+
+void LLLayoutPanel::reshape( S32 width, S32 height, BOOL called_from_parent /*= TRUE*/ )
+{
+	if (width == getRect().getWidth() && height == getRect().getHeight()) return;
+
+	if (!mIgnoreReshape && mAutoResize == false)
 	{
-		mFractionalSize += height - llround(mFractionalSize);
+		mTargetDim = (mOrientation == LLLayoutStack::HORIZONTAL) ? width : height;
+		LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent());
+		if (stackp)
+		{
+			stackp->mNeedsLayout = true;
+		}
 	}
 	LLPanel::reshape(width, height, called_from_parent);
 }
 
-F32 LLLayoutPanel::getCollapseFactor()
+void LLLayoutPanel::handleReshape(const LLRect& new_rect, bool by_user)
 {
-	if (mOrientation == LLLayoutStack::HORIZONTAL)
+	LLLayoutStack* stackp = dynamic_cast<LLLayoutStack*>(getParent());
+	if (stackp)
 	{
-		F32 collapse_amt = 
-			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getWidth()));
-		return mVisibleAmt * collapse_amt;
+		stackp->mNeedsLayout = true;
+		if (by_user)
+		{
+			// tell layout stack to account for new shape
+			stackp->updatePanelRect(this, new_rect);
+		}
 	}
-	else
-	{
-		F32 collapse_amt = 
-			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getHeight())));
-		return mVisibleAmt * collapse_amt;
-	}
+	LLPanel::handleReshape(new_rect, by_user);
 }
 
 //
 	clip("clip", true),
 	open_time_constant("open_time_constant", 0.02f),
 	close_time_constant("close_time_constant", 0.03f),
+	resize_bar_overlap("resize_bar_overlap", 1),
 	border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))
 {}
 
 LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) 
 :	LLView(p),
-	mMinWidth(0),
-	mMinHeight(0),
 	mPanelSpacing(p.border_size),
 	mOrientation(p.orientation),
 	mAnimate(p.animate),
 	mAnimatedThisFrame(false),
+	mNeedsLayout(true),
 	mClip(p.clip),
 	mOpenTimeConstant(p.open_time_constant),
-	mCloseTimeConstant(p.close_time_constant)
+	mCloseTimeConstant(p.close_time_constant),
+	mResizeBarOverlap(p.resize_bar_overlap)
 {}
 
 LLLayoutStack::~LLLayoutStack()
 {
 	updateLayout();
 
-	e_panel_list_t::iterator panel_it;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	// always clip to stack itself
+	LLLocalClipRect clip(getLocalRect());
+	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
 	{
 		// clip to layout rectangle, not bounding rectangle
-		LLRect clip_rect = (*panel_it)->getRect();
+		LLRect clip_rect = panelp->getRect();
 		// scale clipping rectangle by visible amount
 		if (mOrientation == HORIZONTAL)
 		{
-			clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
+			clip_rect.mRight = clip_rect.mLeft + panelp->getVisibleDim();
 		}
 		else
 		{
-			clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
+			clip_rect.mBottom = clip_rect.mTop - panelp->getVisibleDim();
 		}
 
-		LLPanel* panelp = (*panel_it);
-
-		LLLocalClipRect clip(clip_rect, mClip);
-		// only force drawing invisible children if visible amount is non-zero
-		drawChild(panelp, 0, 0, !clip_rect.isEmpty());
+		{LLLocalClipRect clip(clip_rect, mClip);
+			// only force drawing invisible children if visible amount is non-zero
+			drawChild(panelp, 0, 0, !clip_rect.isEmpty());
+		}
 	}
 	mAnimatedThisFrame = false;
 }
 	{
 		mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
 		delete embedded_panelp;
+		updateFractionalSizes();
+		mNeedsLayout = true;
 	}
 
-	// need to update resizebars
-
-	calcMinExtents();
-
 	LLView::removeChild(view);
 }
 
 	LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child);
 	if (panelp)
 	{
-		panelp->mFractionalSize = (mOrientation == HORIZONTAL)
-									? panelp->getRect().getWidth()
-									: panelp->getRect().getHeight();
 		panelp->setOrientation(mOrientation);
 		mPanels.push_back(panelp);
+		createResizeBar(panelp);
+		mNeedsLayout = true;
 	}
-	return LLView::addChild(child, tab_group);
-}
+	BOOL result = LLView::addChild(child, tab_group);
 
-void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front)
-{
-	LLLayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move);
-	LLLayoutPanel* embedded_target_panel = move_to_front ? *mPanels.begin() : findEmbeddedPanel(target_panel);
-
-	if (!embedded_panel_to_move || !embedded_target_panel || embedded_panel_to_move == embedded_target_panel)
-	{
-		llwarns << "One of the panels was not found in stack or NULL was passed instead of valid panel" << llendl;
-		return;
-	}
-	e_panel_list_t::iterator it = std::find(mPanels.begin(), mPanels.end(), embedded_panel_to_move);
-	mPanels.erase(it);
-	it = move_to_front ? mPanels.begin() : std::find(mPanels.begin(), mPanels.end(), embedded_target_panel);
-	mPanels.insert(it, embedded_panel_to_move);
+	updateFractionalSizes();
+	return result;
 }
 
 void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate)
 	}
 }
 
-void LLLayoutStack::removePanel(LLPanel* panel)
-{
-	removeChild(panel);
-}
-
 void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
 {
 	LLLayoutPanel* panel_container = findEmbeddedPanel(panel);
 	if (!panel_container) return;
 
 	panel_container->mCollapsed = collapsed;
-}
-
-void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize)
-{
-	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
-
-	if (panel)
-	{
-		panel->mAutoResize = auto_resize;
-	}
-}
-
-void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_resize)
-{
-	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
-
-	if (panel)
-	{
-		panel->mUserResize = user_resize;
-	}
-}
-
-bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_dimp)
-{
-	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
-
-	if (panel && min_dimp)
-	{
-		*min_dimp = panel->getRelevantMinDim();
-	}
-
-	return NULL != panel;
-}
-
-bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_dimp)
-{
-	LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
-
-	if (panel)
-	{
-		if (max_dimp) *max_dimp = panel->mMaxDim;
-	}
-
-	return NULL != panel;
+	mNeedsLayout = true;
 }
 
 static LLFastTimer::DeclareTimer FTM_UPDATE_LAYOUT("Update LayoutStacks");
-void LLLayoutStack::updateLayout(BOOL force_resize)
-{
+
+void LLLayoutStack::updateLayout()
+{	
 	LLFastTimer ft(FTM_UPDATE_LAYOUT);
-	static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0);
-	calcMinExtents();
-	createResizeBars();
 
-	// calculate current extents
-	F32 total_size = 0.f;
+	if (!mNeedsLayout) return;
 
-	//
-	// animate visibility
-	//
-	e_panel_list_t::iterator panel_it;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end();	++panel_it)
+	bool animation_in_progress = animatePanels();
+	F32 total_visible_fraction = 0.f;
+	F32 total_open_fraction = 0.f;
+	S32 space_to_distribute = (mOrientation == HORIZONTAL)
+							? getRect().getWidth()
+							: getRect().getHeight();
+
+	// first, assign minimum dimensions
+	LLLayoutPanel* panelp = NULL;
+	BOOST_FOREACH(panelp, mPanels)
 	{
-		LLLayoutPanel* panelp = (*panel_it);
-		if (panelp->getVisible()) 
+		if (panelp->mAutoResize)
 		{
-			if (mAnimate)
+			panelp->mTargetDim = panelp->getRelevantMinDim();
+			if (!panelp->mCollapsed && panelp->getVisible())
 			{
-				if (!mAnimatedThisFrame)
-				{
-					panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(mOpenTimeConstant));
-					if (panelp->mVisibleAmt > 0.99f)
-					{
-						panelp->mVisibleAmt = 1.f;
-					}
-				}
-			}
-			else
-			{
-				panelp->mVisibleAmt = 1.f;
+				total_open_fraction += panelp->mFractionalSize;
 			}
 		}
-		else // not visible
+		space_to_distribute -= panelp->getVisibleDim() + llround((F32)mPanelSpacing * panelp->getVisibleAmount());
+		total_visible_fraction += panelp->mFractionalSize;
+	}
+
+	llassert(total_visible_fraction < 1.01f);
+
+	// don't need spacing after last panel
+	space_to_distribute += panelp ? llround((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0;
+
+	F32 fraction_distributed = 0.f;
+	if (space_to_distribute > 0 && total_visible_fraction > 0.f)
+	{	// give space proportionally to visible auto resize panels
+		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
 		{
-			if (mAnimate)
+			if (panelp->mAutoResize)
 			{
-				if (!mAnimatedThisFrame)
-				{
-					panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
-					if (panelp->mVisibleAmt < 0.001f)
-					{
-						panelp->mVisibleAmt = 0.f;
-					}
-				}
+				F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction);
+				S32 delta = llround((F32)space_to_distribute * fraction_to_distribute);
+				fraction_distributed += fraction_to_distribute;
+				panelp->mTargetDim += delta;
 			}
-			else
-			{
-				panelp->mVisibleAmt = 0.f;
-			}
-		}
-
-		F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f;
-		panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
-
-        total_size += panelp->mFractionalSize * panelp->getCollapseFactor();
-        // want n-1 panel gaps for n panels
-		if (panel_it != mPanels.begin())
-		{
-			total_size += mPanelSpacing;
 		}
 	}
 
-	S32 num_resizable_panels = 0;
-	F32 shrink_headroom_available = 0.f;
-	F32 shrink_headroom_total = 0.f;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		LLLayoutPanel* panelp = (*panel_it);
+	if (fraction_distributed < total_visible_fraction)
+	{	// distribute any left over pixels to non-collapsed, visible panels
+		F32 fraction_left = total_visible_fraction - fraction_distributed;
+		S32 space_left = llround((F32)space_to_distribute * (fraction_left / total_visible_fraction));
 
-		// panels that are not fully visible do not count towards shrink headroom
-		if (panelp->getCollapseFactor() < 1.f) 
+		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
 		{
-			continue;
-		}
-
-		F32 cur_size = panelp->mFractionalSize;
-		F32 min_size = (F32)panelp->getRelevantMinDim();
-		
-		// if currently resizing a panel or the panel is flagged as not automatically resizing
-		// only track total available headroom, but don't use it for automatic resize logic
-		if (panelp->mResizeBar->hasMouseCapture() 
-			|| (!panelp->mAutoResize 
-				&& !force_resize))
-		{
-			shrink_headroom_total += cur_size - min_size;
-		}
-		else
-		{
-			num_resizable_panels++;
-			
-			shrink_headroom_available += cur_size - min_size;
-			shrink_headroom_total += cur_size - min_size;
+			if (panelp->mAutoResize 
+				&& !panelp->mCollapsed 
+				&& panelp->getVisible())
+			{
+				S32 space_for_panel = llmax(0, llround((F32)space_left * (panelp->mFractionalSize / total_open_fraction)));
+				panelp->mTargetDim += space_for_panel;
+				space_left -= space_for_panel;
+				total_open_fraction -= panelp->mFractionalSize;
+			}
 		}
 	}
 
-	// calculate how many pixels need to be distributed among layout panels
-	// positive means panels need to grow, negative means shrink
-	F32 pixels_to_distribute = (mOrientation == HORIZONTAL)
-							? getRect().getWidth() - total_size
-							: getRect().getHeight() - total_size;
+	F32 cur_pos = (mOrientation == HORIZONTAL) ? 0.f : (F32)getRect().getHeight();
 
-	// now we distribute the pixels...
-	F32 cur_x = 0.f;
-	F32 cur_y = (F32)getRect().getHeight();
-
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
 	{
-		LLLayoutPanel* panelp = (*panel_it);
-
-		F32 min_size = panelp->getRelevantMinDim();
-		F32 delta_size = 0.f;
-
-		// if panel can automatically resize (not animating, and resize flag set)...
-		if (panelp->getCollapseFactor() == 1.f 
-			&& (force_resize || panelp->mAutoResize) 
-			&& !panelp->mResizeBar->hasMouseCapture()) 
-		{
-			if (pixels_to_distribute < 0.f)
-			{
-				// shrink proportionally to amount over minimum
-				// so we can do this in one pass
-				delta_size = (shrink_headroom_available > 0.f) 
-					? pixels_to_distribute * ((F32)(panelp->mFractionalSize - min_size) / shrink_headroom_available) 
-					: 0.f;
-				shrink_headroom_available -= (panelp->mFractionalSize - min_size);
-			}
-			else
-			{
-				// grow all elements equally
-				delta_size = pixels_to_distribute / (F32)num_resizable_panels;
-				num_resizable_panels--;
-			}
-			
-			panelp->mFractionalSize = llmax(min_size, panelp->mFractionalSize + delta_size);
-			pixels_to_distribute -= delta_size;
-		}
-
-		// adjust running headroom count based on new sizes
-		shrink_headroom_total += delta_size;
+		F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim);
+		F32 panel_visible_dim = panelp->getVisibleDim();
 
 		LLRect panel_rect;
 		if (mOrientation == HORIZONTAL)
 		{
-			panel_rect.setLeftTopAndSize(llround(cur_x), 
-										llround(cur_y), 
-										llround(panelp->mFractionalSize), 
+			panel_rect.setLeftTopAndSize(llround(cur_pos),
+										getRect().getHeight(),
+										llround(panel_dim),
 										getRect().getHeight());
 		}
 		else
 		{
-			panel_rect.setLeftTopAndSize(llround(cur_x), 
-										llround(cur_y), 
-										getRect().getWidth(), 
-										llround(panelp->mFractionalSize));
+			panel_rect.setLeftTopAndSize(0,
+										llround(cur_pos),
+										getRect().getWidth(),
+										llround(panel_dim));
 		}
+		panelp->setIgnoreReshape(true);
 		panelp->setShape(panel_rect);
+		panelp->setIgnoreReshape(false);
 
-		LLRect resize_bar_rect = panel_rect;
+		LLRect resize_bar_rect(panel_rect);
+
+		F32 panel_spacing = (F32)mPanelSpacing * panelp->getVisibleAmount();
 		if (mOrientation == HORIZONTAL)
 		{
-			resize_bar_rect.mLeft = panel_rect.mRight - resize_bar_overlap;
-			resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + resize_bar_overlap;
-		}
-		else
-		{
-			resize_bar_rect.mTop = panel_rect.mBottom + resize_bar_overlap;
-			resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - resize_bar_overlap;
-		}
-		(*panel_it)->mResizeBar->setRect(resize_bar_rect);
+			resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap;
+			resize_bar_rect.mRight = panel_rect.mRight + (S32)(llround(panel_spacing)) + mResizeBarOverlap;
 
-		F32 size = ((*panel_it)->mFractionalSize * (*panel_it)->getCollapseFactor()) + (F32)mPanelSpacing;
-		if (mOrientation == HORIZONTAL)
-		{
-			cur_x += size;
+			cur_pos += panel_visible_dim + panel_spacing;
 		}
 		else //VERTICAL
 		{
-			cur_y -= size;
+			resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap;
+			resize_bar_rect.mBottom = panel_rect.mBottom - (S32)(llround(panel_spacing)) - mResizeBarOverlap;
+
+			cur_pos -= panel_visible_dim + panel_spacing;
 		}
+		panelp->mResizeBar->setShape(resize_bar_rect);
 	}
 
-	// update resize bars with new limits
-	LLLayoutPanel* last_resizeable_panel = NULL;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		LLLayoutPanel* panelp = (*panel_it);
-		S32 relevant_min = panelp->getRelevantMinDim();
+	updateResizeBarLimits();
 
-		if (mOrientation == HORIZONTAL)
-		{
-			(*panel_it)->mResizeBar->setResizeLimits(
-				relevant_min, 
-				relevant_min + llround(shrink_headroom_total));
-		}
-		else //VERTICAL
-		{
-			(*panel_it)->mResizeBar->setResizeLimits(
-				relevant_min, 
-				relevant_min + llround(shrink_headroom_total));
-		}
-
-		// toggle resize bars based on panel visibility, resizability, etc
-		BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
-		(*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
-
-		if ((*panel_it)->mUserResize || (*panel_it)->mAutoResize)
-		{
-			last_resizeable_panel = (*panel_it);
-		}
-	}
-
-	// hide last resize bar as there is nothing past it
-	// resize bars need to be in between two resizable panels
-	if (last_resizeable_panel)
-	{
-		last_resizeable_panel->mResizeBar->setVisible(FALSE);
-	}
-
-	// not enough room to fit existing contents
-	if (force_resize == FALSE
-		// layout did not complete by reaching target position
-		&& ((mOrientation == VERTICAL && llround(cur_y) != -mPanelSpacing)
-			|| (mOrientation == HORIZONTAL && llround(cur_x) != getRect().getWidth() + mPanelSpacing)))
-	{
-		// do another layout pass with all stacked elements contributing
-		// even those that don't usually resize
-		llassert_always(force_resize == FALSE);
-		updateLayout(TRUE);
-	}
-
-	 mAnimatedThisFrame = true;
+	// clear animation flag at end, since panel resizes will set it
+	// and leave it set if there is any animation in progress
+	mNeedsLayout = animation_in_progress;
 } // end LLLayoutStack::updateLayout
 
-
 LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
 {
 	if (!panelp) return NULL;
 
 	e_panel_list_t::const_iterator panel_it;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	BOOST_FOREACH(LLLayoutPanel* p, mPanels)
 	{
-		if ((*panel_it) == panelp)
+		if (p == panelp)
 		{
-			return *panel_it;
+			return p;
 		}
 	}
 	return NULL;
 {
 	LLLayoutPanel* result = NULL;
 
-	for (e_panel_list_t::const_iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	BOOST_FOREACH(LLLayoutPanel* p, mPanels)
 	{
-		LLLayoutPanel* p = *panel_it;
-
 		if (p->getName() == name)
 		{
 			result = p;
 	return result;
 }
 
-// Compute sum of min_width or min_height of children
-void LLLayoutStack::calcMinExtents()
+void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)
 {
-	mMinWidth = 0;
-	mMinHeight = 0;
-
-	e_panel_list_t::iterator panel_it;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	BOOST_FOREACH(LLLayoutPanel* lp, mPanels)
 	{
-		if (mOrientation == HORIZONTAL)
-		{
-            mMinWidth += (*panel_it)->getRelevantMinDim();
-			if (panel_it != mPanels.begin())
-			{
-				mMinWidth += mPanelSpacing;
-			}
-		}
-		else //VERTICAL
-		{
-			mMinHeight += (*panel_it)->getRelevantMinDim();
-			if (panel_it != mPanels.begin())
-			{
-				mMinHeight += mPanelSpacing;
-			}
-		}
-	}
-}
-
-void LLLayoutStack::createResizeBars()
-{
-	for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		LLLayoutPanel* lp = (*panel_it);
 		if (lp->mResizeBar == NULL)
 		{
 			LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
 			LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params);
 			lp->mResizeBar = resize_bar;
 			LLView::addChild(resize_bar, 0);
-
-			// bring all resize bars to the front so that they are clickable even over the panels
-			// with a bit of overlap
-			for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-			{
-				LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
-				sendChildToFront(resize_barp);
-			}
 		}
 	}
+	// bring all resize bars to the front so that they are clickable even over the panels
+	// with a bit of overlap
+	for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	{
+		LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
+		sendChildToFront(resize_barp);
+	}
 }
 
 // update layout stack animations, etc. once per frame
 		it->updateLayout();
 	}
 }
+
+void LLLayoutStack::updateFractionalSizes()
+{
+	F32 total_resizable_dim = 0;
+	S32 num_auto_resize_panels = 0;
+
+	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
+	{
+		if (panelp->mAutoResize)
+		{
+			total_resizable_dim += llmax(0, panelp->getLayoutDim() - panelp->getRelevantMinDim());
+			num_auto_resize_panels++;
+		}
+	}
+
+	F32 total_fractional_size = 0.f;
+	
+	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
+	{
+		if (panelp->mAutoResize)
+		{
+			F32 panel_resizable_dim = llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim()));
+			panelp->mFractionalSize = panel_resizable_dim > 0.f 
+										? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE)
+										: MIN_FRACTIONAL_SIZE;
+			total_fractional_size += panelp->mFractionalSize;
+			llassert(!llisnan(panelp->mFractionalSize));
+		}
+	}
+
+	if (total_fractional_size == 0.f)
+	{ // equal distribution
+		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
+		{
+			if (panelp->mAutoResize)
+			{
+				panelp->mFractionalSize = MAX_FRACTIONAL_SIZE / (F32)num_auto_resize_panels;
+			}
+		}
+	}
+	else
+	{ // renormalize
+		BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
+		{
+			if (panelp->mAutoResize)
+			{
+				panelp->mFractionalSize /= total_fractional_size;
+			}
+		}
+	}
+}
+
+bool LLLayoutStack::animatePanels()
+{
+	bool animation_in_progress = false;
+	
+	//
+	// animate visibility
+	//
+	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
+	{
+		if (panelp->getVisible())
+		{
+			if (mAnimate && panelp->mVisibleAmt < 1.f)
+			{
+				if (!mAnimatedThisFrame)
+				{
+					panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(mOpenTimeConstant));
+					if (panelp->mVisibleAmt > 0.99f)
+					{
+						panelp->mVisibleAmt = 1.f;
+					}
+				}
+				
+				animation_in_progress = true;
+			}
+			else
+			{
+				if (panelp->mVisibleAmt != 1.f)
+				{
+					panelp->mVisibleAmt = 1.f;
+					animation_in_progress = true;
+				}
+			}
+		}
+		else // not visible
+		{
+			if (mAnimate && panelp->mVisibleAmt > 0.f)
+			{
+				if (!mAnimatedThisFrame)
+				{
+					panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
+					if (panelp->mVisibleAmt < 0.001f)
+					{
+						panelp->mVisibleAmt = 0.f;
+					}
+				}
+
+				animation_in_progress = true;
+			}
+			else
+			{
+				if (panelp->mVisibleAmt != 0.f)
+				{
+					panelp->mVisibleAmt = 0.f;
+					animation_in_progress = true;
+				}
+			}
+		}
+
+		F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f;
+		if (panelp->mCollapseAmt != collapse_state)
+		{
+			if (!mAnimatedThisFrame)
+			{
+				panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
+			}
+			animation_in_progress = true;
+			
+			if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f)
+			{
+				panelp->mCollapseAmt = collapse_state;
+			}
+		}
+	}
+
+	mAnimatedThisFrame = true;
+
+	return animation_in_progress;
+}
+
+void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& new_rect )
+{
+	S32 new_dim = (mOrientation == HORIZONTAL)
+					? new_rect.getWidth()
+					: new_rect.getHeight();
+	S32 delta_dim = new_dim - resized_panel->getVisibleDim();
+	if (delta_dim == 0) return;
+
+	F32 total_visible_fraction = 0.f;
+	F32 delta_auto_resize_headroom = 0.f;
+	F32 total_auto_resize_headroom = 0.f;
+
+	LLLayoutPanel* other_resize_panel = NULL;
+	LLLayoutPanel* following_panel = NULL;
+
+	BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels)
+	{
+		if (panelp->mAutoResize)
+		{
+			total_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim());
+			total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor();
+		}
+
+		if (panelp == resized_panel)
+		{
+			other_resize_panel = following_panel;
+		}
+
+		if (panelp->getVisible() && !panelp->mCollapsed)
+		{
+			following_panel = panelp;
+		}
+	}
+
+	if (resized_panel->mAutoResize == FALSE)
+	{
+		delta_auto_resize_headroom += -delta_dim;
+	}
+	if (other_resize_panel && other_resize_panel->mAutoResize == FALSE)
+	{
+		delta_auto_resize_headroom += delta_dim;
+	}
+
+	F32 fraction_given_up = 0.f;
+	F32 fraction_remaining = 1.f;
+	F32 updated_auto_resize_headroom = total_auto_resize_headroom + delta_auto_resize_headroom;
+
+	enum
+	{
+		BEFORE_RESIZED_PANEL,
+		RESIZED_PANEL,
+		NEXT_PANEL,
+		AFTER_RESIZED_PANEL
+	} which_panel = BEFORE_RESIZED_PANEL;
+
+	BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
+	{
+		if (!panelp->getVisible() || panelp->mCollapsed) continue;
+
+		if (panelp == resized_panel)
+		{
+			which_panel = RESIZED_PANEL;
+		}
+
+		switch(which_panel)
+		{
+		case BEFORE_RESIZED_PANEL:
+			if (panelp->mAutoResize)
+			{	// freeze current size as fraction of overall auto_resize space
+				F32 fractional_adjustment_factor = total_auto_resize_headroom / updated_auto_resize_headroom;
+				F32 new_fractional_size = llclamp(panelp->mFractionalSize * fractional_adjustment_factor,
+													MIN_FRACTIONAL_SIZE,
+													MAX_FRACTIONAL_SIZE);
+				F32 fraction_delta = (new_fractional_size - panelp->mFractionalSize);
+				fraction_given_up -= fraction_delta;
+				fraction_remaining -= panelp->mFractionalSize;
+				panelp->mFractionalSize += fraction_delta;
+				llassert(!llisnan(panelp->mFractionalSize));
+			}
+			else
+			{
+				// leave non auto-resize panels alone
+			}
+			break;
+		case RESIZED_PANEL:
+			if (panelp->mAutoResize)
+			{	// freeze new size as fraction
+				F32 new_fractional_size = (updated_auto_resize_headroom == 0.f)
+					? MAX_FRACTIONAL_SIZE
+					: llclamp((F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);
+				fraction_given_up -= new_fractional_size - panelp->mFractionalSize;
+				fraction_remaining -= panelp->mFractionalSize;
+				panelp->mFractionalSize = new_fractional_size;
+				llassert(!llisnan(panelp->mFractionalSize));
+			}
+			else
+			{	// freeze new size as original size
+				panelp->mTargetDim = new_dim;
+				fraction_remaining -= fraction_given_up;
+			}
+			which_panel = NEXT_PANEL;
+			break;
+		case NEXT_PANEL:
+			if (panelp->mAutoResize)
+			{
+				fraction_remaining -= panelp->mFractionalSize;
+				if (fraction_given_up != 0.f)
+				{
+					panelp->mFractionalSize = llclamp(panelp->mFractionalSize + fraction_given_up, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);
+					fraction_given_up = 0.f;
+				}
+				else
+				{
+					F32 new_fractional_size = llclamp((F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom) 
+														/ updated_auto_resize_headroom,
+													MIN_FRACTIONAL_SIZE,
+													MAX_FRACTIONAL_SIZE);
+					fraction_given_up -= new_fractional_size - panelp->mFractionalSize;
+					panelp->mFractionalSize = new_fractional_size;
+				}
+			}
+			else
+			{
+				panelp->mTargetDim -= delta_dim;
+			}
+			which_panel = AFTER_RESIZED_PANEL;
+			break;
+		case AFTER_RESIZED_PANEL:
+			if (panelp->mAutoResize)
+			{
+				panelp->mFractionalSize = llclamp(panelp->mFractionalSize + (panelp->mFractionalSize / fraction_remaining) * fraction_given_up,
+												MIN_FRACTIONAL_SIZE,
+												MAX_FRACTIONAL_SIZE);
+			}
+		default:
+			break;
+		}
+	}
+}
+
+void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	mNeedsLayout = true;
+	LLView::reshape(width, height, called_from_parent);
+}
+
+void LLLayoutStack::updateResizeBarLimits()
+{
+	LLLayoutPanel* previous_visible_panelp = NULL;
+	BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels)
+	{
+		if (!visible_panelp->getVisible() || visible_panelp->mCollapsed)
+		{
+			visible_panelp->mResizeBar->setVisible(FALSE);
+			continue;
+		}
+
+		// toggle resize bars based on panel visibility, resizability, etc
+		if (previous_visible_panelp
+			&& (visible_panelp->mUserResize || previous_visible_panelp->mUserResize)				// one of the pair is user resizable
+			&& (visible_panelp->mAutoResize || visible_panelp->mUserResize)							// current panel is resizable
+			&& (previous_visible_panelp->mAutoResize || previous_visible_panelp->mUserResize))		// previous panel is resizable
+		{
+			visible_panelp->mResizeBar->setVisible(TRUE);
+			S32 previous_panel_headroom = previous_visible_panelp->getVisibleDim() - previous_visible_panelp->getRelevantMinDim();
+			visible_panelp->mResizeBar->setResizeLimits(visible_panelp->getRelevantMinDim(), 
+														visible_panelp->getVisibleDim() + previous_panel_headroom);
+		}
+		else
+		{
+			visible_panelp->mResizeBar->setVisible(FALSE);
+		}
+
+		previous_visible_panelp = visible_panelp;
+	}
+}

indra/llui/lllayoutstack.h

  *
  * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2010, Linden Reshasearch, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 								clip;
 		Optional<F32>			open_time_constant,
 								close_time_constant;
+		Optional<S32>			resize_bar_overlap;
 
 		Params();
 	};
 	/*virtual*/ void removeChild(LLView*);
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0);
+	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+
 
 	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
 
-	S32 getMinWidth() const { return mMinWidth; }
-	S32 getMinHeight() const { return mMinHeight; }
-	
 	typedef enum e_animate
 	{
 		NO_ANIMATE,
 	} EAnimate;
 
 	void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE);
-	void removePanel(LLPanel* panel);
 	void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
 	S32 getNumPanels() { return mPanels.size(); }
-	/**
-	 * Moves panel_to_move before target_panel inside layout stack (both panels should already be there).
-	 * If move_to_front is true target_panel is ignored and panel_to_move is moved to the beginning of mPanels
-	 */
-	void movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front = false);
 
-	void updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize);
-	void setPanelUserResize(const std::string& panel_name, BOOL user_resize);
-	
-	/**
-	 * Gets minimal dimension along layout_stack axis of the specified by name panel.
-	 *
-	 * @returns true if specified by panel_name internal panel exists, false otherwise.
-	 */
-	bool getPanelMinSize(const std::string& panel_name, S32* min_dimp);
+	void updateLayout();
 
-	/**
-	 * Gets maximal dimension along layout_stack axis of the specified by name panel.
-	 *
-	 * @returns true if specified by panel_name internal panel exists, false otherwise.
-	 */
-	bool getPanelMaxSize(const std::string& panel_name, S32* max_dim);
-	
-	void updateLayout(BOOL force_resize = FALSE);
-	
 	S32 getPanelSpacing() const { return mPanelSpacing; }
-	BOOL getAnimate () const { return mAnimate; }
-	void setAnimate (BOOL animate) { mAnimate = animate; }
 	
 	static void updateClass();
 
 protected:
 	LLLayoutStack(const Params&);
 	friend class LLUICtrlFactory;
+	friend class LLLayoutPanel;
 
 private:
-	void createResizeBars();
-	void calcMinExtents();
+	void updateResizeBarLimits();
+	bool animatePanels();
+	void createResizeBar(LLLayoutPanel* panel);
 
 	const ELayoutOrientation mOrientation;
 
 
 	LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
 	LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const;
+	void updateFractionalSizes();
+	void updatePanelRect( LLLayoutPanel* param1, const LLRect& new_rect );
 
-	S32 mMinWidth;  // calculated by calcMinExtents
-	S32 mMinHeight;  // calculated by calcMinExtents
 	S32 mPanelSpacing;
 
 	// true if we already applied animation this frame
 	bool mAnimatedThisFrame;
 	bool mAnimate;
 	bool mClip;
-	F32 mOpenTimeConstant;
-	F32 mCloseTimeConstant;
+	F32  mOpenTimeConstant;
+	F32  mCloseTimeConstant;
+	bool mNeedsLayout;
+	S32  mResizeBarOverlap;
 }; // end class LLLayoutStack
 
 
 	struct Params : public LLInitParam::Block<Params, LLPanel::Params>
 	{
 		Optional<S32>			expanded_min_dim,
-								min_dim,
-								max_dim;
+								min_dim;
 		Optional<bool>			user_resize,
 								auto_resize;
 
 
 	void initFromParams(const Params& p);
 
+	void handleReshape(const LLRect& new_rect, bool by_user);
+
 	void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+	
 
-	S32 getMinDim() const { return mMinDim; }
-	void setMinDim(S32 value) { mMinDim = value; if (!mExpandedMinDimSpecified) mExpandedMinDim = value; }
+	void setVisible(BOOL visible);
 
-	S32 getMaxDim() const { return mMaxDim; }
-	void setMaxDim(S32 value) { mMaxDim = value; }
+	S32 getLayoutDim() const;
+	S32 getMinDim() const { return (mMinDim >= 0 || mAutoResize) ? llmax(0, mMinDim) : getLayoutDim(); }
+	void setMinDim(S32 value) { mMinDim = value; }
 
-	S32 getExpandedMinDim() const { return mExpandedMinDim; }
-	void setExpandedMinDim(S32 value) { mExpandedMinDim = value; mExpandedMinDimSpecified = true; }
+	S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : mMinDim; }
+	void setExpandedMinDim(S32 value) { mExpandedMinDim = value; }
 	
 	S32 getRelevantMinDim() const
 	{
 		
 		if (!mCollapsed)
 		{
-			min_dim = mExpandedMinDim;
+			min_dim = getExpandedMinDim();
 		}
 		
 		return min_dim;
 	}
 
-	F32 getCollapseFactor();
-	void setOrientation(LLLayoutStack::ELayoutOrientation orientation) { mOrientation = orientation; }
+	F32 getAutoResizeFactor() const;
+	F32 getVisibleAmount() const;
+	S32 getVisibleDim() const;
+
+	void setOrientation(LLLayoutStack::ELayoutOrientation orientation);
+	void storeOriginalDim();
+
+	void setIgnoreReshape(bool ignore) { mIgnoreReshape = ignore; }
 
 protected:
 	LLLayoutPanel(const Params& p);
 	
-	bool	mExpandedMinDimSpecified;
+	const bool	mAutoResize;
+	const bool	mUserResize;
+
 	S32		mExpandedMinDim;
-	
 	S32		mMinDim;
-	S32		mMaxDim;
-	bool	mAutoResize;
-	bool	mUserResize;
 	bool	mCollapsed;
 	F32		mVisibleAmt;
 	F32		mCollapseAmt;
 	F32		mFractionalSize;
+	S32		mTargetDim;
+	bool	mIgnoreReshape;
 	LLLayoutStack::ELayoutOrientation mOrientation;
 	class LLResizeBar* mResizeBar;
 };

indra/llui/llresizebar.cpp

 
 BOOL LLResizeBar::handleMouseDown(S32 x, S32 y, MASK mask)
 {
+	if (!canResize()) return FALSE;
+
 	// Route future Mouse messages here preemptively.  (Release on mouse up.)
 	// No handler needed for focus lost since this clas has no state that depends on it.
 	gFocusMgr.setMouseCapture( this );
 		handled = TRUE;
 	}
 
-	if( handled )
+	if( handled && canResize() )
 	{
 		switch( mSide )
 		{

indra/llui/llresizebar.h

 	void			setResizeLimits( S32 min_size, S32 max_size ) { mMinSize = min_size; mMaxSize = max_size; }
 	void			setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; }
 	void			setAllowDoubleClickSnapping(BOOL allow) { mAllowDoubleClickSnapping = allow; }
+	bool			canResize() { return getEnabled() && mMaxSize > mMinSize; }
 
 private:
 	S32				mDragLastScreenX;

indra/llui/llscrollcontainer.cpp

 		focusFirstItem();
 	}
 
-	// Draw background
-	if( mIsOpaque )
+	if (getRect().isValid()) 
 	{
-		F32 alpha = getCurrentTransparency();
+		// Draw background
+		if( mIsOpaque )
+		{
+			F32 alpha = getCurrentTransparency();
 
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha);
-	}
+			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			gl_rect_2d(mInnerRect, mBackgroundColor.get() % alpha);
+		}
 	
-	// Draw mScrolledViews and update scroll bars.
-	// get a scissor region ready, and draw the scrolling view. The
-	// scissor region ensures that we don't draw outside of the bounds
-	// of the rectangle.
-	if( mScrolledView )
-	{
-		updateScroll();
+		// Draw mScrolledViews and update scroll bars.
+		// get a scissor region ready, and draw the scrolling view. The
+		// scissor region ensures that we don't draw outside of the bounds
+		// of the rectangle.
+		if( mScrolledView )
+		{
+			updateScroll();
 
-		// Draw the scrolled area.
+			// Draw the scrolled area.
+			{
+				S32 visible_width = 0;
+				S32 visible_height = 0;
+				BOOL show_v_scrollbar = FALSE;
+				BOOL show_h_scrollbar = FALSE;
+				calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
+
+				LLLocalClipRect clip(LLRect(mInnerRect.mLeft, 
+						mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height,
+						mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0),
+						mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0)
+						));
+				drawChild(mScrolledView);
+			}
+		}
+
+		// Highlight border if a child of this container has keyboard focus
+		if( mBorder->getVisible() )
 		{
-			S32 visible_width = 0;
-			S32 visible_height = 0;
-			BOOL show_v_scrollbar = FALSE;
-			BOOL show_h_scrollbar = FALSE;
-			calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
+			mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) );
+		}
 
-			LLLocalClipRect clip(LLRect(mInnerRect.mLeft, 
-					mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height,
-					mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0),
-					mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0)
-					));
-			drawChild(mScrolledView);
-		}
-	}
-
-	// Highlight border if a child of this container has keyboard focus
-	if( mBorder->getVisible() )
-	{
-		mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus(this) );
-	}
-
-	// Draw all children except mScrolledView
-	// Note: scrollbars have been adjusted by above drawing code
-	for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin();
-		 child_iter != getChildList()->rend(); ++child_iter)
-	{
-		LLView *viewp = *child_iter;
-		if( sDebugRects )
+		// Draw all children except mScrolledView
+		// Note: scrollbars have been adjusted by above drawing code
+		for (child_list_const_reverse_iter_t child_iter = getChildList()->rbegin();
+			 child_iter != getChildList()->rend(); ++child_iter)
 		{
-			sDepth++;
-		}
-		if( (viewp != mScrolledView) && viewp->getVisible() )
-		{
-			drawChild(viewp);
-		}
-		if( sDebugRects )
-		{
-			sDepth--;
+			LLView *viewp = *child_iter;
+			if( sDebugRects )
+			{
+				sDepth++;
+			}
+			if( (viewp != mScrolledView) && viewp->getVisible() )
+			{
+				drawChild(viewp);
+			}
+			if( sDebugRects )
+			{
+				sDepth--;
+			}
 		}
 	}
 } // end draw

indra/llui/llview.cpp

 		{
 			child_list_reverse_iter_t child = child_iter++;
 			LLView *viewp = *child;
+			
+			if (viewp == NULL)
+			{
+				continue;
+			}
 
 			if (viewp->getVisible() && viewp->getRect().isValid())
 			{

indra/llui/llwindowshade.cpp

 
 	notification_area->reshape(notification_area->getRect().getWidth(), 
 		llclamp(message_rect.getHeight() + 15, 
-				llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT),
+				llmax(mFormHeight, MIN_NOTIFICATION_AREA_HEIGHT),
 				MAX_NOTIFICATION_AREA_HEIGHT));
 
 	LLUICtrl::draw();
 	{
 		hide();
 	}
-	else if (notification_area->getCollapseFactor() < 0.01f)
+	else if (notification_area->getVisibleAmount() < 0.01f)
 	{
 		displayLatestNotification();
 	}
 
-	if (!notification_area->getVisible() && (notification_area->getCollapseFactor() < 0.001f))
+	if (!notification_area->getVisible() && (notification_area->getVisibleAmount() < 0.001f))
 	{
 		getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false);
 		setMouseOpaque(false);
 	getChild<LLTextBox>("notification_text")->setColor(color);
 }
 
+bool LLWindowShade::isShown() const
+{
+	return getChildRef<LLLayoutPanel>("notification_area").getVisible();
+}
+
 void LLWindowShade::setCanClose(bool can_close)
 {
 	getChildView("close_panel")->setVisible(can_close);

indra/llui/llwindowshade.h

 	void show(LLNotificationPtr);
 	/*virtual*/ void draw();
 	void hide();
+	
+	bool isShown() const;
+
 	void setBackgroundImage(LLUIImage* image);
 	void setTextColor(LLColor4 color);
 	void setCanClose(bool can_close);

indra/llwindow/llwindowwin32.cpp

 
 	LLMemType m1(LLMemType::MTYPE_GATHER_INPUT);
 
-	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && msg_count < MAX_MESSAGE_PER_UPDATE)
+	while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
 	{
 		mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput");
 		TranslateMessage(&msg);

indra/newview/CMakeLists.txt

     llfloaternotificationsconsole.cpp
     llfloaterobjectweights.cpp
     llfloateropenobject.cpp
+    llfloateroutbox.cpp
     llfloaterpay.cpp
     llfloaterperms.cpp
     llfloaterpostprocess.cpp
     llmaniprotate.cpp
     llmanipscale.cpp
     llmaniptranslate.cpp
+    llmarketplacefunctions.cpp
+    llmarketplacenotifications.cpp
     llmediactrl.cpp
     llmediadataclient.cpp
     llmemoryview.cpp
     llpanelmaininventory.cpp
     llpanelmarketplaceinbox.cpp
     llpanelmarketplaceinboxinventory.cpp
-    llpanelmarketplaceoutbox.cpp
     llpanelmarketplaceoutboxinventory.cpp
     llpanelmediasettingsgeneral.cpp
     llpanelmediasettingspermissions.cpp
     llfloaternotificationsconsole.h
     llfloaterobjectweights.h
     llfloateropenobject.h
+    llfloateroutbox.h
     llfloaterpay.h
     llfloaterperms.h
     llfloaterpostprocess.h
     llmaniprotate.h
     llmanipscale.h
     llmaniptranslate.h
+    llmarketplacefunctions.h
+    llmarketplacenotifications.h
     llmediactrl.h
     llmediadataclient.h
     llmemoryview.h
     llpanelmaininventory.h
     llpanelmarketplaceinbox.h
     llpanelmarketplaceinboxinventory.h
-    llpanelmarketplaceoutbox.h
     llpanelmarketplaceoutboxinventory.h
     llpanelmediasettingsgeneral.h
     llpanelmediasettingspermissions.h

indra/newview/app_settings/commands.xml

            is_running_function="Floater.IsOpen"
            is_running_parameters="moveview"
            />
+  <command name="outbox"
+           available_in_toybox="false"
+           icon="Command_Outbox_Icon"
+           label_ref="Command_Outbox_Label"
+           tooltip_ref="Command_Outbox_Tooltip"
+           execute_function="Floater.ToggleOrBringToFront"
+           execute_parameters="outbox"
+           is_running_function="Floater.IsOpen"
+           is_running_parameters="outbox"
+           />
   <command name="people"
            available_in_toybox="true"
            icon="Command_People_Icon"

indra/newview/app_settings/settings.xml

 		<key>Value</key>
 		<integer>0</integer>
 	</map>
-    <key>InventoryMarketplaceUserStatus</key>
-    <map>
-      <key>Comment</key>
-      <string>Marketplace user status.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string />
+	<key>InventoryOutboxLogging</key>
+	<map>
+		<key>Comment</key>
+		<string>Enable debug output associated with the Merchant Outbox.</string>
+		<key>Persist</key>
+		<integer>1</integer>
+		<key>Type</key>
+		<string>Boolean</string>
+		<key>Value</key>
+		<integer>0</integer>
+	</map>
+    <key>InventoryOutboxMaxFolderCount</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum number of subfolders allowed in a listing in the merchant outbox.</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>21</integer>
+    </map>
+    <key>InventoryOutboxMaxFolderDepth</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum number of nested levels of subfolders allowed in a listing in the merchant outbox.</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>4</integer>
+    </map>
+    <key>InventoryOutboxMaxItemCount</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum number of items allowed in a listing in the merchant outbox.</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>200</integer>
     </map>
     <key>InventorySortOrder</key>
     <map>
       <key>Value</key>
       <real>3</real>
     </map>
-    <key>UIResizeBarOverlap</key>
-    <map>
-      <key>Comment</key>
-      <string>Size of UI resize bar overlap</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>S32</string>
-      <key>Value</key>
-      <real>1</real>
-    </map>
     <key>UIScaleFactor</key>
     <map>
       <key>Comment</key>

indra/newview/llappviewer.cpp

 #include "llwindow.h"
 #include "llviewerstats.h"
 #include "llviewerstatsrecorder.h"
+#include "llmarketplacefunctions.h"
+#include "llmarketplacenotifications.h"
 #include "llmd5.h"
 #include "llmeshrepository.h"
 #include "llpumpio.h"
 
 	// update media focus
 	LLViewerMediaFocus::getInstance()->update();
+	
+	// Update marketplace
+	LLMarketplaceInventoryImporter::update();
+	LLMarketplaceInventoryNotifications::update();
 
 	// objects and camera should be in sync, do LOD calculations now
 	{

indra/newview/llavataractions.cpp

 		LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
 		if (sidepanel_inventory)
 		{
-			inventory_selected_uuids = sidepanel_inventory->getInboxOrOutboxSelectionList();
+			inventory_selected_uuids = sidepanel_inventory->getInboxSelectionList();
 		}
 	}
 

indra/newview/llchathistory.cpp

 	panel_p.has_border = false;
 	panel_p.mouse_opaque = false;
 	panel_p.min_dim = 30;
-	panel_p.max_dim = S32_MAX;
 	panel_p.auto_resize = true;
 	panel_p.user_resize = false;
 

indra/newview/llchicletbar.cpp

 {
 	const std::string& PANEL_CHICLET_NAME	= "chiclet_list_panel";
 
-	S32 get_panel_min_width(LLLayoutStack* stack, LLView* panel)
-	{
-		S32 minimal_width = 0;
-		llassert(stack);
-		if ( stack && panel && panel->getVisible() )
-		{
-			stack->getPanelMinSize(panel->getName(), &minimal_width);
-		}
-		return minimal_width;
-	}
-
-	S32 get_panel_max_width(LLLayoutStack* stack, LLPanel* panel)
-	{
-		S32 max_width = 0;
-		llassert(stack);
-		if ( stack && panel && panel->getVisible() )
-		{
-			stack->getPanelMaxSize(panel->getName(), &max_width);
-		}
-		return max_width;
-	}
-
 	S32 get_curr_width(LLUICtrl* ctrl)
 	{
 		S32 cur_width = 0;
 	{
 		// Firstly, update layout stack to ensure we deal with correct panel sizes.
 		{
-			BOOL saved_anim = mToolbarStack->getAnimate();
-			// Set chiclet panel to be autoresized by default.
-			mToolbarStack->updatePanelAutoResize(PANEL_CHICLET_NAME, TRUE);
-			// Disable animation to prevent layout updating in several frames.
-			mToolbarStack->setAnimate(FALSE);
 			// Force the updating of layout to reset panels collapse factor.
 			mToolbarStack->updateLayout();
-			// Restore animate state.
-			mToolbarStack->setAnimate(saved_anim);
 		}
 
 		// chiclet bar is narrowed

indra/newview/llfloaterland.cpp

 		}
 
 		mSeeAvatarsCtrl->set(parcel->getSeeAVs());
-		mSeeAvatarsCtrl->setLabel(getString("see_avs_text"));
 		mSeeAvatarsCtrl->setEnabled(can_change_options && parcel->getHaveNewParcelLimitData());
 
 		BOOL can_change_landing_point = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, 
 				mListBanned->addNameItem(entry.mID, ADD_DEFAULT, TRUE, suffix);
 			}
 		}
-		
-		LLCheckBoxWithTBAcess* maturity_checkbox = (LLCheckBoxWithTBAcess*) getChild<LLCheckBoxCtrl>( "public_access");
-		LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
-		if(region)
-		{
-			LLTextBox* maturity_textbox = maturity_checkbox->getTextBox();
-			insert_maturity_into_textbox(maturity_textbox, gFloaterView->getParentFloater(this), getString("allow_public_access"));
-			maturity_checkbox->reshape(maturity_checkbox->getRect().getWidth(), maturity_checkbox->getRect().getHeight(), FALSE);
-		}
-		else
-		{
-			std::string maturity_string = getString("allow_public_access");
-			size_t maturity_pos = maturity_string.find(MATURITY);
-
-			if (maturity_pos != std::string::npos)
-			{
-				maturity_string.replace(maturity_pos, MATURITY.length(), std::string(""));
-			}
-
-			maturity_checkbox->setLabel(maturity_string);
-		}
 
 		if(parcel->getRegionDenyAnonymousOverride())
 		{

indra/newview/llfloaternotificationsconsole.cpp

 void LLFloaterNotificationConsole::removeChannel(const std::string& name)
 {
 	LLPanel* panelp = getChild<LLPanel>(name);
-	getChildRef<LLLayoutStack>("notification_channels").removePanel(panelp);
+	getChildRef<LLView>("notification_channels").removeChild(panelp);
 	delete panelp;
 
 	updateResizeLimits();

indra/newview/llfloateroutbox.cpp

+/** 
+ * @file llfloateroutbox.cpp
+ * @brief Implementation of the merchant outbox window
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloateroutbox.h"
+
+#include "llfloaterreg.h"
+#include "llfolderview.h"
+#include "llinventorybridge.h"
+#include "llinventorymodelbackgroundfetch.h"
+#include "llinventoryobserver.h"
+#include "llinventorypanel.h"
+#include "llmarketplacefunctions.h"
+#include "llnotificationhandler.h"
+#include "llnotificationmanager.h"
+#include "llnotificationsutil.h"
+#include "lltextbox.h"
+#include "lltransientfloatermgr.h"
+#include "lltrans.h"
+#include "llviewernetwork.h"
+#include "llwindowshade.h"
+
+#define USE_WINDOWSHADE_DIALOGS	0
+
+
+///----------------------------------------------------------------------------
+/// LLOutboxNotification class
+///----------------------------------------------------------------------------
+
+bool LLNotificationsUI::LLOutboxNotification::processNotification(const LLSD& notify)
+{
+	LLFloaterOutbox* outbox_floater = LLFloaterReg::getTypedInstance<LLFloaterOutbox>("outbox");
+	
+	outbox_floater->showNotification(notify);
+
+	return false;
+}
+
+
+///----------------------------------------------------------------------------
+/// LLOutboxAddedObserver helper class
+///----------------------------------------------------------------------------
+
+class LLOutboxAddedObserver : public LLInventoryCategoryAddedObserver
+{
+public:
+	LLOutboxAddedObserver(LLFloaterOutbox * outboxFloater)
+		: LLInventoryCategoryAddedObserver()
+		, mOutboxFloater(outboxFloater)
+	{
+	}
+	
+	void done()
+	{
+		for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it)
+		{
+			LLViewerInventoryCategory* added_category = *it;
+			
+			LLFolderType::EType added_category_type = added_category->getPreferredType();
+			
+			if (added_category_type == LLFolderType::FT_OUTBOX)
+			{
+				mOutboxFloater->setupOutbox(added_category->getUUID());
+			}
+		}
+	}
+	
+private:
+	LLFloaterOutbox *	mOutboxFloater;
+};
+
+///----------------------------------------------------------------------------
+/// LLFloaterOutbox
+///----------------------------------------------------------------------------
+
+LLFloaterOutbox::LLFloaterOutbox(const LLSD& key)
+	: LLFloater(key)
+	, mCategoriesObserver(NULL)
+	, mCategoryAddedObserver(NULL)
+	, mImportBusy(false)
+	, mImportButton(NULL)
+	, mInventoryFolderCountText(NULL)
+	, mInventoryImportInProgress(NULL)
+	, mInventoryPlaceholder(NULL)
+	, mInventoryText(NULL)
+	, mInventoryTitle(NULL)
+	, mOutboxId(LLUUID::null)
+	, mOutboxInventoryPanel(NULL)
+	, mOutboxItemCount(0)
+	, mOutboxTopLevelDropZone(NULL)
+	, mWindowShade(NULL)
+{
+}
+
+LLFloaterOutbox::~LLFloaterOutbox()
+{
+	if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
+	{
+		gInventory.removeObserver(mCategoriesObserver);
+	}
+	delete mCategoriesObserver;
+	
+	if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
+	{
+		gInventory.removeObserver(mCategoryAddedObserver);
+	}
+	delete mCategoryAddedObserver;
+}
+
+BOOL LLFloaterOutbox::postBuild()
+{
+	mInventoryFolderCountText = getChild<LLTextBox>("outbox_folder_count");
+	mInventoryImportInProgress = getChild<LLView>("import_progress_indicator");
+	mInventoryPlaceholder = getChild<LLView>("outbox_inventory_placeholder_panel");
+	mInventoryText = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_text");
+	mInventoryTitle = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_title");
+	
+	mImportButton = getChild<LLButton>("outbox_import_btn");
+	mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this));
+
+	mOutboxTopLevelDropZone = getChild<LLPanel>("outbox_generic_drag_target");
+
+	LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this));
+
+	return TRUE;
+}
+
+void LLFloaterOutbox::onClose(bool app_quitting)
+{
+	if (mWindowShade)
+	{
+		delete mWindowShade;
+
+		mWindowShade = NULL;
+	}
+}
+
+void LLFloaterOutbox::onOpen(const LLSD& key)
+{
+	//
+	// Look for an outbox and set up the inventory API
+	//
+	
+	if (mOutboxId.isNull())
+	{
+		const bool do_not_create_folder = false;
+		const bool do_not_find_in_library = false;
+		
+		const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, do_not_create_folder, do_not_find_in_library);
+		
+		if (outbox_id.isNull())
+		{
+			// Observe category creation to catch outbox creation
+			mCategoryAddedObserver = new LLOutboxAddedObserver(this);
+			gInventory.addObserver(mCategoryAddedObserver);
+		}
+		else
+		{
+			setupOutbox(outbox_id);
+		}
+	}
+	
+	updateView();
+	
+	//
+	// Trigger fetch of outbox contents
+	//
+	
+	fetchOutboxContents();</