diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index 0371b7be7132e76b0a1015a334877465f6c13dc9..b6482e0ec473d7eec8ee85cdf935e374d0e726a8 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -492,26 +492,6 @@ void LLBottomTray::updateContextMenu(S32 x, S32 y, MASK mask)
 	mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Select_All", in_edit_box);
 }
 
-void LLBottomTray::showGestureButton(BOOL visible)
-{
-	setTrayButtonVisibleIfPossible(RS_BUTTON_GESTURES, visible);
-}
-
-void LLBottomTray::showMoveButton(BOOL visible)
-{
-	setTrayButtonVisibleIfPossible(RS_BUTTON_MOVEMENT, visible);
-}
-
-void LLBottomTray::showCameraButton(BOOL visible)
-{
-	setTrayButtonVisibleIfPossible(RS_BUTTON_CAMERA, visible);
-}
-
-void LLBottomTray::showSnapshotButton(BOOL visible)
-{
-	setTrayButtonVisibleIfPossible(RS_BUTTON_SNAPSHOT, visible);
-}
-
 void LLBottomTray::showSpeakButton(bool visible)
 {
 	// Show/hide the button
@@ -936,15 +916,14 @@ void LLBottomTray::log(LLView* panel, const std::string& descr)
 {
 	if (NULL == panel) return;
 	LLView* layout = panel->getParent();
-	lldebugs << descr << ": "
+	LL_DEBUGS("Bottom Tray Rects") << descr << ": "
 		<< "panel: " << panel->getName()
 		<< ", rect: " << panel->getRect()
  
  
-		<< "layout: " << layout->getName()
+		<< " layout: " << layout->getName()
 		<< ", rect: " << layout->getRect()
-		<< llendl
-		; 
+		<< LL_ENDL;
 }
 
 void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
@@ -964,7 +943,9 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
 	if (mNearbyChatBar)			log(mNearbyChatBar, "before");
 	if (mChicletPanel)			log(mChicletPanel, "before");
 
-	// stores width size on which bottom tray is less than width required by its children. EXT-991
+	// Difference between bottom tray width required to fit its children and the actual width. (see EXT-991)
+	// Positive value means that bottom tray is not wide enough.
+	// Negative value means that there is free space.
 	static S32 extra_shrink_width = 0;
 	bool should_be_reshaped = true;
 
@@ -986,11 +967,9 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
 		// bottom tray is narrowed
 		if (delta_width < 0)
 		{
-			if (extra_shrink_width > 0)
+			if (extra_shrink_width > 0) // not enough space
 			{
-				// is world rect was extra shrunk and decreasing again only update this value
-				// to delta_width negative
-				extra_shrink_width -= delta_width; // use "-=" because delta_width is negative
+				extra_shrink_width += llabs(delta_width);
 				should_be_reshaped = false;
 			}
 			else
@@ -1001,13 +980,13 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
 				width += extra_shrink_width;
 			}
 		}
-		// bottom tray is widen
+		// bottom tray is widened
 		else
 		{
 			if (extra_shrink_width > delta_width)
 			{
-				// Less than minimum width is more than increasing (delta_width) 
-				// only reduce it value and make no reshape
+				// Still not enough space.
+				// Only subtract the delta from the required delta and don't reshape.
 				extra_shrink_width -= delta_width;
 				should_be_reshaped = false;
 			}
@@ -1047,6 +1026,7 @@ void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
 		{
 			mDesiredNearbyChatWidth = new_width;
 			processChatbarCustomization(new_width);
+			lldebugs << "Setting nearby chat bar width to " << new_width << " px" << llendl;
 			mChatBarContainer->reshape(new_width, mChatBarContainer->getRect().getHeight());
 		}
 		needs_restore_custom_state = false;
@@ -1058,30 +1038,28 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
 {
 	bool still_should_be_processed = true;
 
-	const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
-	const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
+	const S32 chiclet_panel_shrink_headroom = getChicletPanelShrinkHeadroom();
 
 	// There are four steps of processing width decrease. If in one of them required width was reached,
 	// further are not needed.
 	// 1. Decreasing width of chiclet panel.
-	if (chiclet_panel_width > chiclet_panel_min_width)
+	if (chiclet_panel_shrink_headroom > 0)
 	{
 		// we have some space to decrease chiclet panel
-		S32 panel_delta_min = chiclet_panel_width - chiclet_panel_min_width;
-
-		S32 delta_panel = llmin(-delta_width, panel_delta_min);
+		S32 shrink_by = llmin(-delta_width, chiclet_panel_shrink_headroom);
 
 		lldebugs << "delta_width: " << delta_width
-			<< ", panel_delta_min: " << panel_delta_min
-			<< ", delta_panel: " << delta_panel
+			<< ", panel_delta_min: " << chiclet_panel_shrink_headroom
+			<< ", shrink_by: " << shrink_by
 			<< llendl;
 
-		// is chiclet panel width enough to process resizing?
-		delta_width += panel_delta_min;
+		// is chiclet panel wide enough to process resizing?
+		delta_width += chiclet_panel_shrink_headroom;
 
 		still_should_be_processed = delta_width < 0;
 
-		mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - delta_panel, mChicletPanel->getParent()->getRect().getHeight());
+		lldebugs << "Shrinking chiclet panel by " << shrink_by << " px" << llendl;
+		mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - shrink_by, mChicletPanel->getParent()->getRect().getHeight());
 		log(mChicletPanel, "after processing panel decreasing via chiclet panel");
 
 		lldebugs << "RS_CHICLET_PANEL" 
@@ -1105,7 +1083,7 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
 
 		S32 delta_panel = llmin(-delta_width, panel_delta_min);
 
-		// whether chatbar panel width is enough to process resizing?
+		// is chatbar panel wide enough to process resizing?
 		delta_width += panel_delta_min;
 
 		still_should_be_processed = delta_width < 0;
@@ -1113,6 +1091,7 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
 		// chatbar should only be shrunk here, not stretched
 		if(delta_panel > 0)
 		{
+			lldebugs << "Shrinking nearby chat bar by " << delta_panel << " px " << llendl;
 			mChatBarContainer->reshape(mNearbyChatBar->getRect().getWidth() - delta_panel, mChatBarContainer->getRect().getHeight());
 		}
 
@@ -1144,6 +1123,7 @@ S32 LLBottomTray::processWidthDecreased(S32 delta_width)
 			{
 				S32 compensative_width = nearby_needed_width > buttons_freed_width ? buttons_freed_width : nearby_needed_width; 
 				log(mNearbyChatBar, "before applying compensative width");
+				lldebugs << "Extending nearby chat bar by " << compensative_width << " px" << llendl;
 				mChatBarContainer->reshape(mChatBarContainer->getRect().getWidth() + compensative_width, mChatBarContainer->getRect().getHeight() );
 				log(mNearbyChatBar, "after applying compensative width");
 				lldebugs << buttons_freed_width << llendl;
@@ -1158,52 +1138,46 @@ void LLBottomTray::processWidthIncreased(S32 delta_width)
 {
 	if (delta_width <= 0) return;
 
-	const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
-	static const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
-
-	const S32 available_width_chiclet = chiclet_panel_width - chiclet_panel_min_width;
+	// how much room we have to show hidden buttons
+	S32 available_width = delta_width + getChicletPanelShrinkHeadroom();
 
-	// how many room we have to show hidden buttons
-	S32 total_available_width = delta_width + available_width_chiclet;
-
-	lldebugs << "Processing extending, available width:"
-		<< ", chiclets - " << available_width_chiclet
-		<< ", total - " << total_available_width
-		<< llendl;
+	lldebugs << "Distributing (" << getChicletPanelShrinkHeadroom()
+		<< " + " << delta_width << ") = " << available_width << " px" << llendl;
 
-	S32 available_width = total_available_width;
+	// 1. Try showing buttons that have been auto-hidden.
+	S32 processed_width = processShowButtons(available_width);
+	lldebugs << "processed_width = " << processed_width << ", delta_width = " << delta_width << llendl;
 
-	processShowButtons(available_width);
+	lldebugs << "Available_width after showing buttons: " << available_width << llendl;
 
-	// if we have to show/extend some buttons but resized delta width is not enough...
-	S32 processed_width = total_available_width - available_width;
+	// If the newly shown buttons have consumed more than delta_width pixels,
+	// shrink the chiclet panel.
 	if (processed_width > delta_width)
 	{
-		// ... let's shrink nearby chat & chiclet panels
-		S32 required_to_process_width = processed_width;
-
 		// 1. use delta width of resizing
-		required_to_process_width -= delta_width;
+		S32 shrink_by = processed_width - delta_width;
 
 		// 2. use width available via decreasing of chiclet panel
-		if (required_to_process_width > 0)
+		if (shrink_by > 0)
 		{
-			mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - required_to_process_width, mChicletPanel->getParent()->getRect().getHeight());
+			lldebugs << "Shrinking chiclet panel by " << shrink_by << " px" << llendl;
+			mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - shrink_by, mChicletPanel->getParent()->getRect().getHeight());
 			log(mChicletPanel, "after applying compensative width for chiclets: ");
-			lldebugs << required_to_process_width << llendl;
+			lldebugs << shrink_by << llendl;
 		}
 
+		// shown buttons take some space, rest should be processed by nearby chatbar & chiclet panels
+		delta_width -= processed_width;
 	}
 
-	// shown buttons take some space, rest should be processed by nearby chatbar & chiclet panels
-	delta_width -= processed_width;
-
-
-	// how many space can nearby chatbar take?
-	S32 chatbar_panel_width_ = mChatBarContainer->getRect().getWidth();
-	if (delta_width > 0 && chatbar_panel_width_ < mDesiredNearbyChatWidth)
+	// 2. Expand the nearby chat bar if needed.
+	S32 chatbar_panel_width = mChatBarContainer->getRect().getWidth();
+	lldebugs << "delta_width = " << delta_width
+		<< ", chatbar_panel_width = " << chatbar_panel_width
+		<< ", mDesiredNearbyChatWidth = " << mDesiredNearbyChatWidth << llendl;
+	if (delta_width > 0 && chatbar_panel_width < mDesiredNearbyChatWidth)
 	{
-		S32 delta_panel_max = mDesiredNearbyChatWidth - chatbar_panel_width_;
+		S32 delta_panel_max = mDesiredNearbyChatWidth - chatbar_panel_width;
 		S32 delta_panel = llmin(delta_width, delta_panel_max);
 		lldebugs << "Unprocesed delta width: " << delta_width
 			<< ", can be applied to chatbar: " << delta_panel_max
@@ -1211,17 +1185,25 @@ void LLBottomTray::processWidthIncreased(S32 delta_width)
 			<< llendl;
 
 		delta_width -= delta_panel_max;
-		mChatBarContainer->reshape(chatbar_panel_width_ + delta_panel, mChatBarContainer->getRect().getHeight());
+		lldebugs << "Extending nearby chat bar by " << delta_panel << " px " << llendl;
+		mChatBarContainer->reshape(chatbar_panel_width + delta_panel, mChatBarContainer->getRect().getHeight());
 		log(mNearbyChatBar, "applied unprocessed delta width");
 	}
+
+	// 3. Expand buttons that have been auto-shrunk,
+	// if we haven't yet consumed all the available headroom.
 	if (delta_width > 0)
 	{
-		processExtendButtons(delta_width);
+		S32 available_width = delta_width + getChicletPanelShrinkHeadroom();
+		processExtendButtons(available_width);
 	}
 }
 
-void LLBottomTray::processShowButtons(S32& available_width)
+S32 LLBottomTray::processShowButtons(S32& available_width)
 {
+	lldebugs << "Distributing " << available_width << " px" << llendl;
+	S32 original_available_width = available_width;
+
 	// process buttons from left to right
 	resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
 	const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
@@ -1234,37 +1216,20 @@ void LLBottomTray::processShowButtons(S32& available_width)
 		// try to show next button
 		processShowButton(*it, available_width);
 	}
+
+	return original_available_width - available_width;
 }
 
 bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32& available_width)
 {
-	lldebugs << "Trying to show object type: " << shown_object_type << llendl;
-
-	LLPanel* panel = getButtonPanel(shown_object_type);
-	if (NULL == panel)
+	// Check if the button was previously auto-hidden (due to lack of space).
+	if (!isAutoHidden(shown_object_type))
 	{
-		lldebugs << "There is no object to process for state: " << shown_object_type << llendl;
 		return false;
 	}
-	bool can_be_shown = canButtonBeShown(shown_object_type);
-	if (can_be_shown)
-	{
-		//validate if we have enough room to show this button
-		const S32 required_width = panel->getRect().getWidth();
-		can_be_shown = available_width >= required_width;
-		if (can_be_shown)
-		{
-			available_width -= required_width;
-
-			setTrayButtonVisible(shown_object_type, true);
 
-			lldebugs << "processed object type: " << shown_object_type
-				<< ", rest available width: " << available_width
-				<< llendl;
-			mResizeState &= ~shown_object_type;
-		}
-	}
-	return can_be_shown;
+	// Ok. Try showing the button.
+	return showButton(shown_object_type, available_width);
 }
 
 void LLBottomTray::processHideButtons(S32& required_width, S32& buttons_freed_width)
@@ -1289,7 +1254,6 @@ void LLBottomTray::processHideButton(EResizeState processed_object_type, S32& re
 	LLPanel* panel = getButtonPanel(processed_object_type);
 	if (NULL == panel)
 	{
-		lldebugs << "There is no object to process for state: " << processed_object_type << llendl;
 		return;
 	}
 
@@ -1304,7 +1268,7 @@ void LLBottomTray::processHideButton(EResizeState processed_object_type, S32& re
 
 		setTrayButtonVisible(processed_object_type, false);
 
-		mResizeState |= processed_object_type;
+		setAutoHidden(processed_object_type, true);
 
 		lldebugs << "processing object type: " << processed_object_type
 			<< ", buttons_freed_width: " << buttons_freed_width
@@ -1369,7 +1333,6 @@ void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32&
 	LLPanel* panel = getButtonPanel(processed_object_type);
 	if (NULL == panel)
 	{
-		lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
 		return;
 	}
 
@@ -1414,122 +1377,130 @@ void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32&
 void LLBottomTray::processExtendButtons(S32& available_width)
 {
 	// do not allow extending any buttons if we have some buttons hidden via resize
-	if (mResizeState & RS_BUTTONS_CAN_BE_HIDDEN) return;
+	if (isAutoHidden(RS_BUTTONS_CAN_BE_HIDDEN)) return;
 
-	// process buttons from left to right
-	resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
-	const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+	lldebugs << "Distributing " << available_width << " px" << llendl;
 
-	// iterate through buttons in the mButtonsProcessOrder first
-	for (; it != it_end; ++it)
+	// First try extending the Speak button.
+	if (available_width > 0)
 	{
-		// is there available space?
-		if (available_width <= 0) break;
-
-		// try to extend next button
-		processExtendButton(*it, available_width);
+		if (!processExtendSpeakButton(available_width))
+		{
+			// The Speak button needs extension but lacks some space.
+			// Don't extend other buttons in this case: the Speak button
+			// should consume the available headroom first.
+			return;
+		}
 	}
 
-	const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
-	static const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
-	const S32 available_width_chiclet = chiclet_panel_width - chiclet_panel_min_width;
+	// Then process the other buttons from left to right.
+	if (available_width > 0)
+	{
+		resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+		const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+		// iterate through buttons in the mButtonsProcessOrder first
+		for (; it != it_end; ++it)
+		{
+			// is there available space?
+			if (available_width <= 0) break;
 
-	// then try to extend Speak button
-	if (available_width > 0 || available_width_chiclet > 0)
+			// try to extend next button
+			processExtendButton(*it, available_width);
+		}
+	}
+}
+
+bool LLBottomTray::processExtendSpeakButton(S32& available_width)
+{
+	if (available_width <= 0)
 	{
-		S32 panel_max_width = mObjectDefaultWidthMap[RS_BUTTON_SPEAK];
-		S32 panel_width = mSpeakPanel->getRect().getWidth();
-		S32 possible_extend_width = panel_max_width - panel_width;
+		llassert(available_width > 0);
+		return true;
+	}
 
-		if (possible_extend_width >= 0 && possible_extend_width <= available_width + available_width_chiclet)  // HACK: this button doesn't change size so possible_extend_width will be 0
+	const S32 panel_max_width = mObjectDefaultWidthMap[RS_BUTTON_SPEAK];
+	const S32 panel_width = mSpeakPanel->getRect().getWidth();
+	const S32 required_headroom = panel_max_width - panel_width;
+
+	if (panel_width < panel_max_width) // if the button isn't extended already
+	{
+		if (available_width < required_headroom) // not enough space
 		{
-			mSpeakBtn->setLabelVisible(true);
-			mSpeakPanel->reshape(panel_max_width, mSpeakPanel->getRect().getHeight());
-			log(mSpeakBtn, "speak button is extended");
+			lldebugs << "Need (" << required_headroom << " - " << available_width << ") = "
+				<< (required_headroom - available_width) << " more px"
+				<< " to extend the Speak button"<< llendl;
 
-			if( available_width > possible_extend_width)
-			{
-				available_width -= possible_extend_width;
-			}
-			else
-			{
-				S32 required_width = possible_extend_width - available_width;
-				available_width = 0;
-				mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - required_width, mChicletPanel->getParent()->getRect().getHeight());
-			}
-			lldebugs << "Extending Speak button panel: " << mSpeakPanel->getName()
-				<< ", extended width: " << possible_extend_width
-				<< ", rest width to process: " << available_width
-				<< llendl;
+			return false; // Don't extend other buttons until we extend Speak.
 		}
+
+		// Reshape the Speak button to its maximum width.
+		mSpeakBtn->setLabelVisible(true);
+		mSpeakPanel->reshape(panel_max_width, mSpeakPanel->getRect().getHeight());
+
+		available_width -= required_headroom;
+		llassert(available_width >= 0);
+
+		lldebugs << "Extending Speak button panel: " << mSpeakPanel->getName()
+			<< ", extended width: " << required_headroom
+			<< ", rest width to process: " << available_width
+			<< llendl;
 	}
+
+	return true;
 }
 
 void LLBottomTray::processExtendButton(EResizeState processed_object_type, S32& available_width)
 {
+	llassert(available_width >= 0);
+
 	LLPanel* panel = getButtonPanel(processed_object_type);
 	if (NULL == panel)
 	{
-		lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
 		return;
 	}
 
 	if (!panel->getVisible()) return;
 
+	// Widen the button up to its maximum width, but by not more than <available_width> px.
 	S32 panel_max_width = mObjectDefaultWidthMap[processed_object_type];
 	S32 panel_width = panel->getRect().getWidth();
-	S32 possible_extend_width = panel_max_width - panel_width;
+	S32 required_headroom = panel_max_width - panel_width;
 
-	if (possible_extend_width > 0)
+	S32 extend_by = llmin(available_width, required_headroom);
+	if (extend_by > 0)
 	{
-		// let calculate real width to extend
+		panel->reshape(panel_width + extend_by, panel->getRect().getHeight());
 
-		// 1. apply all possible width
-		available_width -= possible_extend_width;
+		// Decrease amount of headroom available for other panels.
+		available_width -= extend_by;
 
-		// 2. it it is too much... 
-		if (available_width < 0)
-		{
-			// reduce applied extended width to the excessive value.
-			possible_extend_width += available_width;
-			available_width = 0;
-		}
-		panel->reshape(panel_width + possible_extend_width, panel->getRect().getHeight());
-
-		lldebugs << "Extending panel: " << panel->getName()
-			<< ", extended width: " << possible_extend_width
-			<< ", rest width to process: " << available_width
+		lldebugs << "Extending " << panel->getName()
+			<< " by " << extend_by
+			<< " px; remaining available width: " << available_width
 			<< llendl;
 	}
 }
 
 bool LLBottomTray::canButtonBeShown(EResizeState processed_object_type) const
 {
-	// 0. Check if passed button was previously hidden on resize
-	bool can_be_shown = mResizeState & processed_object_type;
-	if (can_be_shown)
-	{
-		// Yes, it was. Lets now check that all buttons before it (that can be hidden on resize)
-		// are already shown
-
-		// process buttons in direct order (from left to right)
-		resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
-		const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+	// Check that all buttons (that can be hidden on resize)
+	// to the left of the given one are already shown.
 
-		// 1. Find and accumulate all buttons types before one passed into the method.
-		MASK buttons_before_mask = RS_NORESIZE;
-		for (; it != it_end; ++it)
-		{
-			const EResizeState button_type = *it;
-			if (button_type == processed_object_type) break;
+	// process buttons in direct order (from left to right)
+	resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+	const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
 
-			buttons_before_mask |= button_type;
-		}
+	MASK buttons_before_mask = RS_NORESIZE;
+	for (; it != it_end; ++it)
+	{
+		const EResizeState button_type = *it;
+		if (button_type == processed_object_type) break;
 
-		// 2. Check if some previous buttons are still hidden on resize
-		can_be_shown = !(buttons_before_mask & mResizeState);
+		buttons_before_mask |= button_type;
 	}
-	return can_be_shown;
+
+	return !isAutoHidden(buttons_before_mask);
 }
 
 void LLBottomTray::initResizeStateContainers()
@@ -1592,6 +1563,7 @@ void LLBottomTray::initButtonsVisibility()
 	setVisibleAndFitWidths(RS_BUTTON_SEARCH, gSavedSettings.getBOOL("ShowSearchButton"));
 	setVisibleAndFitWidths(RS_BUTTON_WORLD_MAP, gSavedSettings.getBOOL("ShowWorldMapButton"));
 	setVisibleAndFitWidths(RS_BUTTON_MINI_MAP, gSavedSettings.getBOOL("ShowMiniMapButton"));
+	lldebugs << "mResizeState = " << resizeStateMaskToString(mResizeState) << llendl;
 }
 
 void LLBottomTray::setButtonsControlsAndListeners()
@@ -1623,12 +1595,53 @@ bool LLBottomTray::toggleShowButton(LLBottomTray::EResizeState button_type, cons
 	return true;
 }
 
+bool LLBottomTray::showButton(EResizeState button_type, S32& available_width)
+{
+	LLPanel* panel = getButtonPanel(button_type);
+	if (NULL == panel)
+	{
+		return false;
+	}
+
+	if (panel->getVisible())
+	{
+		return false;
+	}
+
+	// Check if none of the buttons to the left of the given one was auto-hidden.
+	// (we auto-show the buttons left to right).
+	if (!canButtonBeShown(button_type))
+	{
+		return false;
+	}
+
+	// Make sure we have enough room to show this button.
+	const S32 required_width = panel->getRect().getWidth();
+	if (available_width < required_width)
+	{
+		lldebugs << "Need " << (required_width - available_width) << " more px to show " << resizeStateToString(button_type) << llendl;
+		return false;
+	}
+
+	// All good. Show the button.
+	setTrayButtonVisible(button_type, true);
+
+	// Let the caller know that there is now less available space.
+	available_width -= required_width;
+
+	lldebugs << "Showing button " << resizeStateToString(button_type)
+		<< ", remaining available width: " << available_width
+		<< llendl;
+	setAutoHidden(button_type, false);
+
+	return true;
+}
+
 void LLBottomTray::setTrayButtonVisible(EResizeState shown_object_type, bool visible)
 {
 	LLPanel* panel = getButtonPanel(shown_object_type);
 	if (NULL == panel)
 	{
-		lldebugs << "There is no object to show for state: " << shown_object_type << llendl;
 		return;
 	}
 
@@ -1659,7 +1672,6 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
 	LLPanel* cur_panel = getButtonPanel(object_type);
 	if (NULL == cur_panel)
 	{
-		lldebugs << "There is no object to process for state: " << object_type << llendl;
 		return false;
 	}
 
@@ -1668,17 +1680,13 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
 	if (visible)
 	{
 		// Assume that only chiclet panel can be auto-resized
-		const S32 available_width =
-			mChicletPanel->getParent()->getRect().getWidth() - mChicletPanel->getMinWidth();
+		const S32 available_width = getChicletPanelShrinkHeadroom();
 
 		S32 preferred_width = mObjectDefaultWidthMap[object_type];
 		S32 current_width = cur_panel->getRect().getWidth();
 		S32 result_width = 0;
 		bool decrease_width = false;
 
-		// Mark this button to be shown
-		mResizeState |= object_type;
-
 		if (preferred_width > 0 && available_width >= preferred_width)
 		{
 			result_width = preferred_width;
@@ -1722,7 +1730,11 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
 			}
 			else
 			{
-				// Nothing can be done, give up...
+				lldebugs << "Need " << (minimal_width - available_width - possible_shrunk_width)
+					<< " more px to show " << resizeStateToString(object_type) << llendl;
+
+				// Make the button uppear when we have more available space.
+				setAutoHidden(object_type, true);
 				return false;
 			}
 		}
@@ -1733,7 +1745,7 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
 			current_width = result_width;
 		}
 
-		is_set = processShowButton(object_type, current_width);
+		is_set = showButton(object_type, current_width);
 
 		// Shrink buttons if needed
 		if (is_set && decrease_width)
@@ -1748,7 +1760,8 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
 		setTrayButtonVisible(object_type, false);
 
 		// Mark button NOT to show while future bottom tray extending
-		mResizeState &= ~object_type;
+		lldebugs << "Removing " << resizeStateToString(object_type) << " from mResizeState" << llendl;
+		setAutoHidden(object_type, false);
 
 		// Extend other buttons if need
 		if (delta_width)
@@ -1805,12 +1818,14 @@ void LLBottomTray::processChatbarCustomization(S32 new_width)
 
 	if (delta_width == 0) return;
 
+	{
+		static unsigned dbg_cnt = 0;
+		lldebugs << llformat("*** (%03d) ************************************* %d", delta_width, ++dbg_cnt) << llendl;
+	}
+
 	mDesiredNearbyChatWidth = new_width;
 
-	LLView * chiclet_layout_panel = mChicletPanel->getParent();
-	const S32 chiclet_min_width = get_panel_min_width(mToolbarStack, chiclet_layout_panel);
-	const S32 chiclet_panel_width = chiclet_layout_panel->getRect().getWidth();
-	const S32 available_chiclet_shrink_width = chiclet_panel_width - chiclet_min_width;
+	const S32 available_chiclet_shrink_width = getChicletPanelShrinkHeadroom();
 	llassert(available_chiclet_shrink_width >= 0);
 
 	if (delta_width > 0) // panel gets narrowly
@@ -1829,6 +1844,16 @@ void LLBottomTray::processChatbarCustomization(S32 new_width)
 	}
 }
 
+S32 LLBottomTray::getChicletPanelShrinkHeadroom() const
+{
+	static const S32 min_width = mChicletPanel->getMinWidth();
+	const S32 cur_width = mChicletPanel->getParent()->getRect().getWidth();
+
+	S32 shrink_headroom = cur_width - min_width;
+	llassert(shrink_headroom >= 0); // the panel cannot get narrower than the minimum
+	return shrink_headroom;
+}
+
 // static
 std::string LLBottomTray::resizeStateToString(EResizeState state)
 {
@@ -1854,4 +1879,54 @@ std::string LLBottomTray::resizeStateToString(EResizeState state)
 	return "UNKNOWN_BUTTON";
 }
 
+// static
+std::string LLBottomTray::resizeStateMaskToString(MASK mask)
+{
+	std::string res;
+
+	bool add_delimiter = false;
+    for (U32 i = 0; i < 16; i++)
+    {
+    	EResizeState state = (EResizeState) (1 << i);
+    	if (mask & state)
+    	{
+    		if (!add_delimiter)
+    		{
+    			add_delimiter = true;
+    		}
+    		else
+    		{
+    			res += ", ";
+    		}
+
+			res += resizeStateToString(state);
+    	}
+    }
+
+    if (res.empty())
+    {
+    	res = resizeStateToString(RS_NORESIZE);
+    }
+
+    res += llformat(" (0x%X)", mask);
+    return res;
+}
+
+bool LLBottomTray::isAutoHidden(MASK button_types) const
+{
+	return (mResizeState & button_types) != 0;
+}
+
+void LLBottomTray::setAutoHidden(MASK button_types, bool hide)
+{
+	if (hide)
+	{
+		mResizeState |= button_types;
+	}
+	else
+	{
+		mResizeState &= ~button_types;
+	}
+}
+
 //EOF
diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h
index 04e5f5e9e07f478b25c4e520c29c77717551ada9..52bcd2ddacf90d3db0d72a885f366843794e6b57 100644
--- a/indra/newview/llbottomtray.h
+++ b/indra/newview/llbottomtray.h
@@ -112,10 +112,6 @@ class LLBottomTray
 
 	void showBottomTrayContextMenu(S32 x, S32 y, MASK mask);
 
-	void showGestureButton(BOOL visible);
-	void showMoveButton(BOOL visible);
-	void showCameraButton(BOOL visible);
-	void showSnapshotButton(BOOL visible);
 	void showSpeakButton(bool visible);
 
 	void toggleMovementControls();
@@ -240,8 +236,9 @@ class LLBottomTray
 	 *
 	 * @params[in, out] available_width - reference to available width to be used to show buttons.
 	 * @see processShowButton()
+	 * @return consumed pixels (difference in available width).
 	 */
-	void processShowButtons(S32& available_width);
+	S32 processShowButtons(S32& available_width);
 
 	/**
 	 * Tries to show panel with specified button using available width.
@@ -316,6 +313,20 @@ class LLBottomTray
 	 */
 	void processExtendButtons(S32& available_width);
 
+	/**
+	 * Extends the Speak button if there is anough headroom.
+	 *
+	 * Unlike other buttons, the Speak buttons has only two possible widths:
+	 * the minimal one (without label) and the maximal (default) one.
+	 *
+	 * If the button is at its minimum width there is not enough headroom to
+	 * reshape it to the maximum width, the method does nothing.
+	 *
+	 * @param available_width Available headroom.
+	 * @return false if the button requires extension but there's not enough headroom, true otherwise.
+	 */
+	bool processExtendSpeakButton(S32& available_width);
+
 	/**
 	 * Extends shown button to increase total taken space.
 	 *
@@ -364,6 +375,16 @@ class LLBottomTray
 	 */
 	static bool toggleShowButton(EResizeState button_type, const LLSD& new_visibility);
 
+	/**
+	 * Show the button if there is enough space.
+	 *
+	 * @param[in]      button_type -    type of button to be shown.
+	 * @param[in, out] available_width  amount of available space on the bottom bar.
+	 *
+	 * @return true if button was shown, false that's not possible (not enough space, etc)
+	 */
+	bool showButton(EResizeState button_type, S32& available_width);
+
 	/**
 	 * Sets passed visibility to object specified by resize type.
 	 */
@@ -417,9 +438,27 @@ class LLBottomTray
 	 */
 	void processChatbarCustomization(S32 new_width);
 
+	/**
+	 * @return difference between current chiclet panel width and the minimum.
+	 */
+	S32 getChicletPanelShrinkHeadroom() const;
+
 	/// Get button name for debugging.
 	static std::string resizeStateToString(EResizeState state);
 
+	/// Dump a mask for debugging
+	static std::string resizeStateMaskToString(MASK mask);
+
+	/// @return true if any of the the passed buttons have been auto-hidden due to lack of available space.
+	bool isAutoHidden(MASK button_types) const;
+
+	/**
+	 * (Un)Mark the buttons as hidden.
+	 *
+	 * Auto-hidden buttons are those that re-appear as soon as we have enough available space.
+	 */
+	void setAutoHidden(MASK button_types, bool hide);
+
 	/// Buttons automatically hidden due to lack of space.
 	MASK mResizeState;
 
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
index c8882fd02c724996968da7700f5d18e98f10420a..a6e5e7a219495e5906a385a953bc5dd4969ad57f 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
@@ -47,16 +47,16 @@
          mouse_opaque="false"
 		 name="chat_bar_layout_panel"
          user_resize="true"
-     width="310" >
-      <panel
-		   name="chat_bar"
-			  filename="panel_nearby_chat_bar.xml"
-			  left="0"
-			  height="28"
-        width="308"
-			  top="0"
-			  mouse_opaque="false"
-			  follows="left|right"
+         width="250" >
+          <panel
+            name="chat_bar"
+            filename="panel_nearby_chat_bar.xml"
+            left="0"
+            height="28"
+            width="248"
+            top="0"
+            mouse_opaque="false"
+            follows="left|right"
           />
     </layout_panel>
     <!--
@@ -283,100 +283,100 @@ Disabled for now.
          mouse_opaque="false"
      name="search_btn_panel"
          user_resize="false"
-     width="83">
-      <bottomtray_button
-			  follows="left|right"
-			  height="23"
-			  image_pressed="PushButton_Press"
-			  image_pressed_selected="PushButton_Selected_Press"
-			  image_selected="PushButton_Selected_Press"
-       is_toggle="true"
-       label="Search"
-			  layout="topleft"
-			  left="0"
-       name="search_btn"
-       tool_tip="Shows/hides Search"
-			  top="5"
-			  use_ellipses="true"
-       width="80">
-        <init_callback
-         function="Button.SetFloaterToggle"
-         parameter="search" />
-      </bottomtray_button>
-    </layout_panel>
-    <layout_panel
-		   auto_resize="false"
-     follows="left|right"
-		   height="28"
-		   layout="topleft"
-		   min_height="28"
-     min_width="52"
-		   mouse_opaque="false"
-     name="world_map_btn_panel"
-		   user_resize="false"
-     width="83">
-      <bottomtray_button
-			  follows="left|right"
-			  height="23"
-			  image_pressed="PushButton_Press"
-			  image_pressed_selected="PushButton_Selected_Press"
-			  image_selected="PushButton_Selected_Press"
-       is_toggle="true"
-       label="Map"
-			  layout="topleft"
-			  left="0"
-       name="world_map_btn"
-       tool_tip="Shows/hides World Map"
-			  top="5"
-			  use_ellipses="true"
-       width="80">
-        <init_callback
-         function="Button.SetFloaterToggle"
-         parameter="world_map" />
-      </bottomtray_button>
-    </layout_panel>
-    <layout_panel
-		   auto_resize="false"
-     follows="left|right"
-		   height="28"
-		   layout="topleft"
-		   min_height="28"
-     min_width="52"
-		   mouse_opaque="false"
-     name="mini_map_btn_panel"
-		   user_resize="false"
-     width="83">
-      <bottomtray_button
-			  follows="left|right"
-			  height="23"
-			  image_pressed="PushButton_Press"
-			  image_pressed_selected="PushButton_Selected_Press"
-			  image_selected="PushButton_Selected_Press"
-       is_toggle="true"
-       label="Mini-Map"
-			  layout="topleft"
-			  left="0"
-       name="mini_map_btn"
-       tool_tip="Shows/hides Mini-Map"
-			  top="5"
-			  use_ellipses="true"
-       width="80">
-        <init_callback
-         function="Button.SetFloaterToggle"
-         parameter="mini_map" />
-      </bottomtray_button>
-    </layout_panel>
-    <layout_panel
-		   follows="left|right"
-		   height="30"
-		   layout="topleft"
-		   min_width="95"
-		   mouse_opaque="false"
-		   name="chiclet_list_panel"
-		   top="0"
-		   user_resize="false"
-		   width="189">
-      <!--*NOTE: min_width of the chiclet_panel (chiclet_list) must be the same
+         width="83">
+            <bottomtray_button
+             follows="left|right"
+             height="23"
+             image_pressed="PushButton_Press"
+             image_pressed_selected="PushButton_Selected_Press"
+             image_selected="PushButton_Selected_Press"
+             is_toggle="true"
+             label="Search"
+             layout="topleft"
+             left="0"
+             name="search_btn"
+             tool_tip="Shows/hides Search"
+             top="5"
+             use_ellipses="true"
+             width="80">
+                <init_callback
+                 function="Button.SetFloaterToggle"
+                 parameter="search" />
+            </bottomtray_button>
+        </layout_panel>
+        <layout_panel
+         auto_resize="false"
+         follows="left|right"
+         height="28"
+         layout="topleft"
+         min_height="28"
+         min_width="52"
+         mouse_opaque="false"
+         name="world_map_btn_panel"
+         user_resize="false"
+         width="83">
+            <bottomtray_button
+             follows="left|right"
+             height="23"
+             image_pressed="PushButton_Press"
+             image_pressed_selected="PushButton_Selected_Press"
+             image_selected="PushButton_Selected_Press"
+             is_toggle="true"
+             label="Map"
+             layout="topleft"
+             left="0"
+             name="world_map_btn"
+             tool_tip="Shows/hides World Map"
+             top="5"
+             use_ellipses="true"
+             width="80">
+                <init_callback
+                 function="Button.SetFloaterToggle"
+                 parameter="world_map" />
+            </bottomtray_button>
+        </layout_panel>
+        <layout_panel
+         auto_resize="false"
+         follows="left|right"
+         height="28"
+         layout="topleft"
+         min_height="28"
+         min_width="62"
+         mouse_opaque="false"
+         name="mini_map_btn_panel"
+         user_resize="false"
+         width="83">
+            <bottomtray_button
+             follows="left|right"
+             height="23"
+             image_pressed="PushButton_Press"
+             image_pressed_selected="PushButton_Selected_Press"
+             image_selected="PushButton_Selected_Press"
+             is_toggle="true"
+             label="Mini-Map"
+             layout="topleft"
+             left="0"
+             name="mini_map_btn"
+             tool_tip="Shows/hides Mini-Map"
+             top="5"
+             use_ellipses="true"
+             width="80">
+                <init_callback
+                 function="Button.SetFloaterToggle"
+                 parameter="mini_map" />
+            </bottomtray_button>
+        </layout_panel>
+        <layout_panel
+         follows="left|right"
+         height="30"
+         layout="topleft"
+         min_width="95"
+         mouse_opaque="false"
+         name="chiclet_list_panel"
+         top="0"
+         user_resize="false"
+         width="189">
+<!--*NOTE: min_width of the chiclet_panel (chiclet_list) must be the same
 as for parent layout_panel (chiclet_list_panel) to resize bottom tray properly. EXT-991-->
       <chiclet_panel
              chiclet_padding="4"