From 68d5141fb3ccb5e898caa83e9eab84d76134e28c Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 27 Sep 2011 19:06:02 -0700
Subject: EXP-1258 WIP toggle buttons between icons and icons+text modes fixed
 button layout for icon+text layout stack now uses floating point precision to
 avoid clamping panels to 0

---
 indra/llui/llbutton.cpp      |   2 +
 indra/llui/lllayoutstack.cpp | 252 +++++++++++++++----------------------------
 indra/llui/lllayoutstack.h   |  18 ++--
 indra/llui/lltoolbar.cpp     |  40 ++++---
 4 files changed, 119 insertions(+), 193 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 02ac928dfb..e1bea086b2 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -819,6 +819,7 @@ void LLButton::draw()
 		{
 		case LLFontGL::LEFT:
 			text_left += overlay_width + mImgOverlayLabelSpace;
+			text_width -= overlay_width + mImgOverlayLabelSpace;
 			mImageOverlay->draw(
 				mLeftHPad,
 				center_y - (overlay_height / 2), 
@@ -836,6 +837,7 @@ void LLButton::draw()
 			break;
 		case LLFontGL::RIGHT:
 			text_right -= overlay_width + mImgOverlayLabelSpace;
+			text_width -= overlay_width + mImgOverlayLabelSpace;
 			mImageOverlay->draw(
 				getRect().getWidth() - mRightHPad - overlay_width,
 				center_y - (overlay_height / 2), 
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 0d1f608e61..89b3f671a4 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -55,11 +55,12 @@ LLLayoutPanel::LLLayoutPanel(const Params& p)
  	mMaxDim(p.max_dim), 
  	mAutoResize(p.auto_resize),
  	mUserResize(p.user_resize),
-	mFitContent(p.fit_content),
 	mCollapsed(FALSE),
 	mCollapseAmt(0.f),
 	mVisibleAmt(1.f), // default to fully visible
-	mResizeBar(NULL) 
+	mResizeBar(NULL),
+	mFractionalSize(0.f),
+	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())
@@ -89,9 +90,22 @@ LLLayoutPanel::~LLLayoutPanel()
 	mResizeBar = NULL;
 }
 
-F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation)
+void LLLayoutPanel::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
-	if (orientation == LLLayoutStack::HORIZONTAL)
+	if (mOrientation == LLLayoutStack::HORIZONTAL)
+	{
+		mFractionalSize += width - llround(mFractionalSize);
+	}
+	else
+	{
+		mFractionalSize += height - llround(mFractionalSize);
+	}
+	LLPanel::reshape(width, height, called_from_parent);
+}
+
+F32 LLLayoutPanel::getCollapseFactor()
+{
+	if (mOrientation == LLLayoutStack::HORIZONTAL)
 	{
 		F32 collapse_amt = 
 			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getWidth()));
@@ -105,14 +119,6 @@ F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientati
 	}
 }
 
-void LLLayoutPanel::fitToContent()
-{
-	if (mFitContent)
-	{
-		setShape(calcBoundingRect());
-	}
-}
-
 //
 // LLLayoutStack
 //
@@ -158,11 +164,11 @@ void LLLayoutStack::draw()
 		// scale clipping rectangle by visible amount
 		if (mOrientation == HORIZONTAL)
 		{
-			clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor(mOrientation));
+			clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
 		}
 		else
 		{
-			clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor(mOrientation));
+			clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
 		}
 
 		LLPanel* panelp = (*panel_it);
@@ -202,36 +208,15 @@ bool LLLayoutStack::addChild(LLView* child, S32 tab_group)
 	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);
 	}
 	return LLView::addChild(child, tab_group);
 }
 
-
-S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
-{
-	// if we are spanning our children (crude upward propagation of size)
-	// then don't enforce our size on our children
-	if (mOrientation == HORIZONTAL)
-	{
-		cur_height = llmax(mMinHeight, getRect().getHeight());
-	}
-
-	return cur_height;
-}
-
-S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
-{
-	// if we are spanning our children (crude upward propagation of size)
-	// then don't enforce our size on our children
-	if (mOrientation == VERTICAL)
-	{
-		cur_width = llmax(mMinWidth, getRect().getWidth());
-	}
-
-	return cur_width;
-}
-
 void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front)
 {
 	LLLayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move);
@@ -326,14 +311,15 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 	createResizeBars();
 
 	// calculate current extents
-	S32 total_width = 0;
-	S32 total_height = 0;
+	F32 total_size = 0.f;
 
+	//
+	// animate visibility
+	//
 	e_panel_list_t::iterator panel_it;
 	for (panel_it = mPanels.begin(); panel_it != mPanels.end();	++panel_it)
 	{
 		LLLayoutPanel* panelp = (*panel_it);
-		panelp->fitToContent();
 		if (panelp->getVisible()) 
 		{
 			if (mAnimate)
@@ -371,181 +357,110 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 			}
 		}
 
-		if (panelp->mCollapsed)
-		{
-			panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
-		}
-		else
-		{
-			panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
-		}
+		F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f;
+		panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
 
-		if (mOrientation == HORIZONTAL)
+        total_size += panelp->mFractionalSize * panelp->getCollapseFactor();
+        // want n-1 panel gaps for n panels
+		if (panel_it != mPanels.begin())
 		{
-			// enforce minimize size constraint by default
-			if (panelp->getRect().getWidth() < panelp->getRelevantMinDim())
-			{
-				panelp->reshape(panelp->getRelevantMinDim(), panelp->getRect().getHeight());
-			}
-        	total_width += llround(panelp->getRect().getWidth() * panelp->getCollapseFactor(mOrientation));
-        	// want n-1 panel gaps for n panels
-			if (panel_it != mPanels.begin())
-			{
-				total_width += mPanelSpacing;
-			}
-		}
-		else //VERTICAL
-		{
-			// enforce minimize size constraint by default
-			if (panelp->getRect().getHeight() < panelp->getRelevantMinDim())
-			{
-				panelp->reshape(panelp->getRect().getWidth(), panelp->getRelevantMinDim());
-			}
-			total_height += llround(panelp->getRect().getHeight() * panelp->getCollapseFactor(mOrientation));
-			if (panel_it != mPanels.begin())
-			{
-				total_height += mPanelSpacing;
-			}
+			total_size += mPanelSpacing;
 		}
 	}
 
 	S32 num_resizable_panels = 0;
-	S32 shrink_headroom_available = 0;
-	S32 shrink_headroom_total = 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);
+
 		// panels that are not fully visible do not count towards shrink headroom
-		if ((*panel_it)->getCollapseFactor(mOrientation) < 1.f) 
+		if (panelp->getCollapseFactor() < 1.f) 
 		{
 			continue;
 		}
 
-		S32 relevant_dimension = (mOrientation == HORIZONTAL) ? (*panel_it)->getRect().getWidth() : (*panel_it)->getRect().getHeight();
-		S32 relevant_min = (*panel_it)->getRelevantMinDim();
+		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 ((*panel_it)->mResizeBar->hasMouseCapture() 
-			|| (!(*panel_it)->mAutoResize 
+		if (panelp->mResizeBar->hasMouseCapture() 
+			|| (!panelp->mAutoResize 
 				&& !force_resize))
 		{
-			shrink_headroom_total += relevant_dimension - relevant_min;
+			shrink_headroom_total += cur_size - min_size;
 		}
 		else
 		{
 			num_resizable_panels++;
 			
-			shrink_headroom_available += relevant_dimension - relevant_min;
-			shrink_headroom_total += relevant_dimension - relevant_min;
+			shrink_headroom_available += cur_size - min_size;
+			shrink_headroom_total += cur_size - min_size;
 		}
 	}
 
 	// calculate how many pixels need to be distributed among layout panels
 	// positive means panels need to grow, negative means shrink
-	S32 pixels_to_distribute;
-	if (mOrientation == HORIZONTAL)
-	{
-		pixels_to_distribute = getRect().getWidth() - total_width;
-	}
-	else //VERTICAL
-	{
-		pixels_to_distribute = getRect().getHeight() - total_height;
-	}
+	F32 pixels_to_distribute = (mOrientation == HORIZONTAL)
+							? getRect().getWidth() - total_size
+							: getRect().getHeight() - total_size;
 
 	// now we distribute the pixels...
-	S32 cur_x = 0;
-	S32 cur_y = getRect().getHeight();
+	F32 cur_x = 0.f;
+	F32 cur_y = (F32)getRect().getHeight();
 
 	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
 	{
 		LLLayoutPanel* panelp = (*panel_it);
 
-		S32 cur_width = panelp->getRect().getWidth();
-		S32 cur_height = panelp->getRect().getHeight();
-		S32 new_width = cur_width;
-		S32 new_height = cur_height;
-		S32 relevant_min = panelp->getRelevantMinDim();
-
-		if (mOrientation == HORIZONTAL)
-		{
-			new_width = llmax(relevant_min, new_width);
-		}
-		else
-		{
-			new_height = llmax(relevant_min, new_height);
-		}
-		S32 delta_size = 0;
+		F32 min_size = panelp->getRelevantMinDim();
+		F32 delta_size = 0.f;
 
 		// if panel can automatically resize (not animating, and resize flag set)...
-		if (panelp->getCollapseFactor(mOrientation) == 1.f 
+		if (panelp->getCollapseFactor() == 1.f 
 			&& (force_resize || panelp->mAutoResize) 
 			&& !panelp->mResizeBar->hasMouseCapture()) 
 		{
-			if (mOrientation == HORIZONTAL)
+			if (pixels_to_distribute < 0.f)
 			{
-				// if we're shrinking
-				if (pixels_to_distribute < 0)
-				{
-					// shrink proportionally to amount over minimum
-					// so we can do this in one pass
-					delta_size = (shrink_headroom_available > 0) 
-						? llround((F32)pixels_to_distribute * ((F32)(cur_width - relevant_min) / (F32)shrink_headroom_available)) 
-						: 0;
-					shrink_headroom_available -= (cur_width - relevant_min);
-				}
-				else
-				{
-					// grow all elements equally
-					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
-					num_resizable_panels--;
-				}
-				pixels_to_distribute -= delta_size;
-				new_width = llmax(relevant_min, cur_width + delta_size);
+				// 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
 			{
-				new_width = getDefaultWidth(new_width);
-			}
-
-			if (mOrientation == VERTICAL)
-			{
-				if (pixels_to_distribute < 0)
-				{
-					// shrink proportionally to amount over minimum
-					// so we can do this in one pass
-					delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - relevant_min) / (F32)shrink_headroom_available)) : 0;
-					shrink_headroom_available -= (cur_height - relevant_min);
-				}
-				else
-				{
-					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
-					num_resizable_panels--;
-				}
-				pixels_to_distribute -= delta_size;
-				new_height = llmax(relevant_min, cur_height + delta_size);
-			}
-			else
-			{
-				new_height = getDefaultHeight(new_height);
-			}
-		}
-		else
-		{
-			if (mOrientation == HORIZONTAL)
-			{
-				new_height = getDefaultHeight(new_height);
-			}
-			else // VERTICAL
-			{
-				new_width = getDefaultWidth(new_width);
+				// 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;
 
 		LLRect panel_rect;
-		panel_rect.setLeftTopAndSize(cur_x, cur_y, new_width, new_height);
+		if (mOrientation == HORIZONTAL)
+		{
+			panel_rect.setLeftTopAndSize(llround(cur_x), 
+										llround(cur_y), 
+										llround(panelp->mFractionalSize), 
+										getRect().getHeight());
+		}
+		else
+		{
+			panel_rect.setLeftTopAndSize(llround(cur_x), 
+										llround(cur_y), 
+										getRect().getWidth(), 
+										llround(panelp->mFractionalSize));
+		}
 		panelp->setShape(panel_rect);
 
 		LLRect resize_bar_rect = panel_rect;
@@ -561,13 +476,14 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
 		}
 		(*panel_it)->mResizeBar->setRect(resize_bar_rect);
 
+		F32 size = ((*panel_it)->mFractionalSize * (*panel_it)->getCollapseFactor()) + (F32)mPanelSpacing;
 		if (mOrientation == HORIZONTAL)
 		{
-			cur_x += llround(new_width * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;
+			cur_x += size;
 		}
 		else //VERTICAL
 		{
-			cur_y -= llround(new_height * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;
+			cur_y -= size;
 		}
 	}
 
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index 2ed32a2fa9..5d79505fc3 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -126,8 +126,6 @@ protected:
 private:
 	void createResizeBars();
 	void calcMinExtents();
-	S32 getDefaultHeight(S32 cur_height);
-	S32 getDefaultWidth(S32 cur_width);
 
 	const ELayoutOrientation mOrientation;
 
@@ -161,16 +159,14 @@ public:
 								min_dim,
 								max_dim;
 		Optional<bool>			user_resize,
-								auto_resize,
-								fit_content;
+								auto_resize;
 
 		Params()
 		:	expanded_min_dim("expanded_min_dim", 0),
 			min_dim("min_dim", 0),
 			max_dim("max_dim", 0),
 			user_resize("user_resize", true),
-			auto_resize("auto_resize", true),
-			fit_content("fit_content", false)
+			auto_resize("auto_resize", true)
 		{
 			addSynonym(min_dim, "min_width");
 			addSynonym(min_dim, "min_height");
@@ -183,6 +179,8 @@ public:
 
 	void initFromParams(const Params& p);
 
+	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; }
 
@@ -204,11 +202,12 @@ public:
 		return min_dim;
 	}
 
+	void setOrientation(LLLayoutStack::ELayoutOrientation orientation) { mOrientation = orientation; }
+
 protected:
 	LLLayoutPanel(const Params& p);
 	
-	F32 getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation);
-	void fitToContent();
+	F32 getCollapseFactor();
 
 	bool	mExpandedMinDimSpecified;
 	S32		mExpandedMinDim;
@@ -218,9 +217,10 @@ protected:
 	bool	mAutoResize;
 	bool	mUserResize;
 	bool	mCollapsed;
-	bool	mFitContent;
 	F32		mVisibleAmt;
 	F32		mCollapseAmt;
+	F32		mFractionalSize;
+	LLLayoutStack::ELayoutOrientation mOrientation;
 	class LLResizeBar* mResizeBar;
 };
 
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index 677d50a0c7..57a9151649 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -126,14 +126,13 @@ void LLToolBar::createContextMenu()
 	{
 		// Setup bindings specific to this instance for the context menu options
 
-		LLUICtrl::CommitCallbackRegistry::Registrar& commit_reg = LLUICtrl::CommitCallbackRegistry::defaultRegistrar();
+		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit_reg;
 		commit_reg.add("Toolbars.EnableSetting", boost::bind(&LLToolBar::onSettingEnable, this, _2));
 
-		LLUICtrl::EnableCallbackRegistry::Registrar& enable_reg = LLUICtrl::EnableCallbackRegistry::defaultRegistrar();
+		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_reg;
 		enable_reg.add("Toolbars.CheckSetting", boost::bind(&LLToolBar::isSettingChecked, this, _2));
 
 		// Create the context menu
-
 		LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_toolbars.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
 
 		if (menu)
@@ -146,10 +145,6 @@ void LLToolBar::createContextMenu()
 		{
 			llwarns << "Unable to load toolbars context menu." << llendl;
 		}
-
-		// Remove this instance's bindings
-		commit_reg.remove("Toolbars.EnableSetting");
-		enable_reg.remove("Toolbars.CheckSetting");
 	}
 }
 
@@ -184,7 +179,6 @@ void LLToolBar::initFromParams(const LLToolBar::Params& p)
 	center_panel_p.rect = getLocalRect();
 	center_panel_p.auto_resize = false;
 	center_panel_p.user_resize = false;
-	center_panel_p.fit_content = true;
 	LLLayoutPanel* center_panel = LLUICtrlFactory::create<LLLayoutPanel>(center_panel_p);
 	mCenteringStack->addChild(center_panel);
 
@@ -196,6 +190,11 @@ void LLToolBar::initFromParams(const LLToolBar::Params& p)
 	
 	mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p));
 
+	BOOST_FOREACH(LLCommandId::Params params, p.commands)
+	{
+		addCommand(params);
+	}
+
 	mNeedsLayout = true;
 }
 
@@ -207,8 +206,8 @@ bool LLToolBar::addCommand(const LLCommandId& commandId)
 
 	if (add_command)
 	{
-	mButtonCommands.push_back(commandId);
-	createButtons();
+		mButtonCommands.push_back(commandId);
+		createButtons();
 	}
 
 	return add_command;
@@ -220,9 +219,9 @@ bool LLToolBar::hasCommand(const LLCommandId& commandId) const
 
 	if (commandId != LLCommandId::null)
 	{
-		for (std::list<LLCommandId>::const_iterator cmd = mButtonCommands.begin(); cmd != mButtonCommands.end(); ++cmd)
+		BOOST_FOREACH(LLCommandId cmd, mButtonCommands)
 		{
-			if ((*cmd) == commandId)
+			if (cmd == commandId)
 			{
 				has_command = true;
 				break;
@@ -410,11 +409,11 @@ void LLToolBar::updateLayoutAsNeeded()
 			cur_start = row_pad_start;
 			cur_row += max_row_girth + mPadBetween;
 			max_row_girth = 0;
-	}
+		}
 
-	LLRect button_rect;
-	if (orientation == LLLayoutStack::HORIZONTAL)
-	{
+		LLRect button_rect;
+		if (orientation == LLLayoutStack::HORIZONTAL)
+		{
 			button_rect.setLeftTopAndSize(cur_start, panel_rect.mTop - cur_row, button_clamped_width, button->getRect().getHeight());
 		}
 		else // VERTICAL
@@ -460,6 +459,9 @@ void LLToolBar::updateLayoutAsNeeded()
 		mButtonPanel->reshape(total_girth, max_row_length);
 	}
 
+	// make parent fit button panel
+	mButtonPanel->getParent()->setShape(mButtonPanel->getLocalRect());
+
 	// re-center toolbar buttons
 	mCenteringStack->updateLayout();
 
@@ -470,7 +472,13 @@ void LLToolBar::updateLayoutAsNeeded()
 
 void LLToolBar::draw()
 {
+	if (mButtons.empty()) return;
 	updateLayoutAsNeeded();
+	// rect may have shifted during layout
+	LLUI::popMatrix();
+	LLUI::pushMatrix();
+	LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom, 0.f);
+
 	LLUICtrl::draw();
 }
 
-- 
cgit v1.2.3