From 9273459251a6c59f8fabc50d9eef0b78e092e6fd Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Mon, 10 Oct 2011 17:09:46 +0300
Subject: [PATCH] EXP-1285 FIXED Chiclets moved to the upper right of the
 viewer window. - Floaters dock to chiclets at the bottom. - Floaters docking
 region limited to non-toolbar view. - Chiclet bar is positioned between the
 right toolbar and the minimized floaters stacked at the top left corner by
 default.

---
 indra/llui/lldockcontrol.cpp                  |   2 +-
 indra/newview/CMakeLists.txt                  |   2 +
 indra/newview/llagent.cpp                     |   6 +-
 indra/newview/llchiclet.cpp                   |  12 +-
 indra/newview/llchicletbar.cpp                | 340 ++++++++++++++++++
 indra/newview/llchicletbar.h                  |  99 +++++
 indra/newview/llimfloater.cpp                 |  19 +-
 indra/newview/llimfloater.h                   |   2 -
 indra/newview/llimview.cpp                    |   8 +-
 indra/newview/llimview.h                      |   2 -
 indra/newview/llscriptfloater.cpp             |  31 +-
 indra/newview/llscriptfloater.h               |   2 -
 indra/newview/llsyswellwindow.cpp             |  16 +-
 indra/newview/llsyswellwindow.h               |   5 -
 indra/newview/llviewerwindow.cpp              |  14 +-
 .../default/xui/en/panel_chiclet_bar.xml      | 176 +++++++++
 .../default/xui/en/panel_toolbar_view.xml     |  24 +-
 17 files changed, 680 insertions(+), 80 deletions(-)
 create mode 100644 indra/newview/llchicletbar.cpp
 create mode 100644 indra/newview/llchicletbar.h
 create mode 100644 indra/newview/skins/default/xui/en/panel_chiclet_bar.xml

diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp
index 6e39fcd714f..6397bbd0dec 100644
--- a/indra/llui/lldockcontrol.cpp
+++ b/indra/llui/lldockcontrol.cpp
@@ -92,7 +92,7 @@ void LLDockControl::setDock(LLView* dockWidget)
 
 void LLDockControl::getAllowedRect(LLRect& rect)
 {
-	rect = mDockableFloater->getRootView()->getRect();
+	rect = mDockableFloater->getRootView()->getChild<LLView>("non_toolbar_panel")->getRect();
 }
 
 void LLDockControl::repositionDockable()
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 97ccfeac29e..6cbd76bc71a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -118,6 +118,7 @@ set(viewer_SOURCE_FILES
     llchatitemscontainerctrl.cpp
     llchatmsgbox.cpp
     llchiclet.cpp
+    llchicletbar.cpp
     llclassifiedinfo.cpp
     llclassifiedstatsresponder.cpp
     llcofwearables.cpp
@@ -684,6 +685,7 @@ set(viewer_HEADER_FILES
     llchatitemscontainerctrl.h
     llchatmsgbox.h
     llchiclet.h
+    llchicletbar.h
     llclassifiedinfo.h
     llclassifiedstatsresponder.h
     llcofwearables.h
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 31a73c8c317..10aa67c78f2 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -36,10 +36,10 @@
 #include "llagentwearables.h"
 #include "llagentui.h"
 #include "llanimationstates.h"
-#include "llbottomtray.h"
 #include "llcallingcard.h"
 #include "llcapabilitylistener.h"
 #include "llchannelmanager.h"
+#include "llchicletbar.h"
 #include "llconsole.h"
 #include "llenvmanager.h"
 #include "llfirstuse.h"
@@ -1874,7 +1874,7 @@ void LLAgent::endAnimationUpdateUI()
 			LLPanelTopInfoBar::getInstance()->setVisible(TRUE);
 		}
 
-		LLBottomTray::getInstance()->onMouselookModeOut();
+		LLChicletBar::getInstance()->setVisible(TRUE);
 
 		LLPanelStandStopFlying::getInstance()->setVisible(TRUE);
 
@@ -1978,7 +1978,7 @@ void LLAgent::endAnimationUpdateUI()
 
 		LLPanelTopInfoBar::getInstance()->setVisible(FALSE);
 
-		LLBottomTray::getInstance()->onMouselookModeIn();
+		LLChicletBar::getInstance()->setVisible(FALSE);
 
 		LLPanelStandStopFlying::getInstance()->setVisible(FALSE);
 
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 245157923dd..a0763749032 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -29,7 +29,7 @@
 
 #include "llagent.h"
 #include "llavataractions.h"
-#include "llbottomtray.h"
+#include "llchicletbar.h"
 #include "lleventtimer.h"
 #include "llgroupactions.h"
 #include "lliconctrl.h"
@@ -214,10 +214,10 @@ void LLSysWellChiclet::updateWidget(bool is_window_empty)
 {
 	mButton->setEnabled(!is_window_empty);
 
-	LLSD params;
-	params["well_empty"] = is_window_empty;
-	params["well_name"] = getName();
-	notifyParent(params);
+	if (LLChicletBar::instanceExists())
+	{
+		LLChicletBar::getInstance()->showWellButton(getName(), !is_window_empty);
+	}
 }
 // virtual
 BOOL LLSysWellChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
@@ -297,7 +297,7 @@ void LLIMWellChiclet::createMenu()
 void LLIMWellChiclet::messageCountChanged(const LLSD& session_data)
 {
 	const LLUUID& session_id = session_data["session_id"];
-	const S32 counter = LLBottomTray::getInstance()->getTotalUnreadIMCount();
+	const S32 counter = LLChicletBar::getInstance()->getTotalUnreadIMCount();
 	const bool im_not_visible = !LLFloaterReg::instanceVisible("im_container")
 		&& !LLFloaterReg::instanceVisible("impanel", session_id);
 
diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp
new file mode 100644
index 00000000000..a17e1d13f57
--- /dev/null
+++ b/indra/newview/llchicletbar.cpp
@@ -0,0 +1,340 @@
+/** 
+ * @file llchicletbar.cpp
+ * @brief LLChicletBar class implementation
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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" // must be first include
+
+#include "llchicletbar.h"
+
+// library includes
+#include "llfloaterreg.h"
+#include "lllayoutstack.h"
+
+// newview includes
+#include "llchiclet.h"
+#include "llimfloater.h" // for LLIMFloater
+#include "llsyswellwindow.h"
+
+namespace
+{
+	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;
+		if ( ctrl && ctrl->getVisible() )
+		{
+			cur_width = ctrl->getRect().getWidth();
+		}
+		return cur_width;
+	}
+}
+
+LLChicletBar::LLChicletBar(const LLSD&)
+:	mChicletPanel(NULL),
+	mToolbarStack(NULL)
+{
+	// Firstly add our self to IMSession observers, so we catch session events
+	// before chiclets do that.
+	LLIMMgr::getInstance()->addSessionObserver(this);
+
+	buildFromFile("panel_chiclet_bar.xml");
+}
+
+LLChicletBar::~LLChicletBar()
+{
+	if (!LLSingleton<LLIMMgr>::destroyed())
+	{
+		LLIMMgr::getInstance()->removeSessionObserver(this);
+	}
+}
+
+LLIMChiclet* LLChicletBar::createIMChiclet(const LLUUID& session_id)
+{
+	LLIMChiclet::EType im_chiclet_type = LLIMChiclet::getIMSessionType(session_id);
+
+	switch (im_chiclet_type)
+	{
+	case LLIMChiclet::TYPE_IM:
+		return getChicletPanel()->createChiclet<LLIMP2PChiclet>(session_id);
+	case LLIMChiclet::TYPE_GROUP:
+		return getChicletPanel()->createChiclet<LLIMGroupChiclet>(session_id);
+	case LLIMChiclet::TYPE_AD_HOC:
+		return getChicletPanel()->createChiclet<LLAdHocChiclet>(session_id);
+	case LLIMChiclet::TYPE_UNKNOWN:
+		break;
+	}
+
+	return NULL;
+}
+
+//virtual
+void LLChicletBar::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
+{
+	if (!getChicletPanel()) return;
+
+	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
+	if (!session) return;
+
+	// no need to spawn chiclets for participants in P2P calls called through Avaline
+	if (session->isP2P() && session->isOtherParticipantAvaline()) return;
+
+	if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return;
+
+	LLIMChiclet* chiclet = createIMChiclet(session_id);
+	if(chiclet)
+	{
+		chiclet->setIMSessionName(name);
+		chiclet->setOtherParticipantId(other_participant_id);
+		
+		LLIMFloater::onIMChicletCreated(session_id);
+
+	}
+	else
+	{
+		llwarns << "Could not create chiclet" << llendl;
+	}
+}
+
+//virtual
+void LLChicletBar::sessionRemoved(const LLUUID& session_id)
+{
+	if(getChicletPanel())
+	{
+		// IM floater should be closed when session removed and associated chiclet closed
+		LLIMFloater* iMfloater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);
+		if (iMfloater != NULL)
+		{
+			iMfloater->closeFloater();
+		}
+
+		getChicletPanel()->removeChiclet(session_id);
+	}
+}
+
+void LLChicletBar::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
+{
+	//this is only needed in case of outgoing ad-hoc/group chat sessions
+	LLChicletPanel* chiclet_panel = getChicletPanel();
+	if (chiclet_panel)
+	{
+		//it should be ad-hoc im chiclet or group im chiclet
+		LLChiclet* chiclet = chiclet_panel->findChiclet<LLChiclet>(old_session_id);
+		if (chiclet) chiclet->setSessionId(new_session_id);
+	}
+}
+
+S32 LLChicletBar::getTotalUnreadIMCount()
+{
+	return getChicletPanel()->getTotalUnreadIMCount();
+}
+
+BOOL LLChicletBar::postBuild()
+{
+	mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
+	mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
+
+	showWellButton("im_well", !LLIMWellWindow::getInstance()->isWindowEmpty());
+	showWellButton("notification_well", !LLNotificationWellWindow::getInstance()->isWindowEmpty());
+
+	return TRUE;
+}
+
+void LLChicletBar::showWellButton(const std::string& well_name, bool visible)
+{
+	LLView * panel = findChild<LLView>(well_name + "_panel");
+	if (!panel)	return;
+
+	panel->setVisible(visible);
+}
+
+void LLChicletBar::log(LLView* panel, const std::string& descr)
+{
+	if (NULL == panel) return;
+	LLView* layout = panel->getParent();
+	LL_DEBUGS("Chiclet Bar Rects") << descr << ": "
+		<< "panel: " << panel->getName()
+		<< ", rect: " << panel->getRect()
+		<< " layout: " << layout->getName()
+		<< ", rect: " << layout->getRect()
+		<< LL_ENDL;
+}
+
+void LLChicletBar::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	static S32 debug_calling_number = 0;
+	lldebugs << "**************************************** " << ++debug_calling_number << llendl;
+
+	S32 current_width = getRect().getWidth();
+	S32 delta_width = width - current_width;
+	lldebugs << "Reshaping: "
+		<< ", width: " << width
+		<< ", cur width: " << current_width
+		<< ", delta_width: " << delta_width
+		<< ", called_from_parent: " << called_from_parent
+		<< llendl;
+
+	if (mChicletPanel)			log(mChicletPanel, "before");
+
+	// Difference between chiclet bar width required to fit its children and the actual width. (see EXT-991)
+	// Positive value means that chiclet bar is not wide enough.
+	// Negative value means that there is free space.
+	static S32 extra_shrink_width = 0;
+	bool should_be_reshaped = true;
+
+	if (mChicletPanel && mToolbarStack)
+	{
+		// 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
+		if (delta_width < 0)
+		{
+			if (extra_shrink_width > 0) // not enough space
+			{
+				extra_shrink_width += llabs(delta_width);
+				should_be_reshaped = false;
+			}
+			else
+			{
+				extra_shrink_width = processWidthDecreased(delta_width);
+
+				// increase new width to extra_shrink_width value to not reshape less than chiclet bar minimum
+				width += extra_shrink_width;
+			}
+		}
+		// chiclet bar is widened
+		else
+		{
+			if (extra_shrink_width > delta_width)
+			{
+				// 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;
+			}
+			else if (extra_shrink_width > 0)
+			{
+				// If we have some extra shrink width let's reduce delta_width & width
+				delta_width -= extra_shrink_width;
+				width -= extra_shrink_width;
+				extra_shrink_width = 0;
+			}
+		}
+	}
+
+	if (should_be_reshaped)
+	{
+		lldebugs << "Reshape all children with width: " << width << llendl;
+		LLPanel::reshape(width, height, called_from_parent);
+	}
+
+	if (mChicletPanel)			log(mChicletPanel, "after");
+}
+
+S32 LLChicletBar::processWidthDecreased(S32 delta_width)
+{
+	bool still_should_be_processed = true;
+
+	const S32 chiclet_panel_shrink_headroom = getChicletPanelShrinkHeadroom();
+
+	// Decreasing width of chiclet panel.
+	if (chiclet_panel_shrink_headroom > 0)
+	{
+		// we have some space to decrease chiclet panel
+		S32 shrink_by = llmin(-delta_width, chiclet_panel_shrink_headroom);
+
+		lldebugs << "delta_width: " << delta_width
+			<< ", panel_delta_min: " << chiclet_panel_shrink_headroom
+			<< ", shrink_by: " << shrink_by
+			<< llendl;
+
+		// is chiclet panel wide enough to process resizing?
+		delta_width += chiclet_panel_shrink_headroom;
+
+		still_should_be_processed = delta_width < 0;
+
+		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"
+			<< ", delta_width: " << delta_width
+			<< llendl;
+	}
+
+	S32 extra_shrink_width = 0;
+
+	if (still_should_be_processed)
+	{
+		extra_shrink_width = -delta_width;
+		llwarns << "There is no enough width to reshape all children: "
+			<< extra_shrink_width << llendl;
+	}
+
+	return extra_shrink_width;
+}
+
+S32 LLChicletBar::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;
+}
diff --git a/indra/newview/llchicletbar.h b/indra/newview/llchicletbar.h
new file mode 100644
index 00000000000..224dfbb6470
--- /dev/null
+++ b/indra/newview/llchicletbar.h
@@ -0,0 +1,99 @@
+/** 
+* @file llchicletbar.h
+* @brief LLChicletBar class header file
+*
+* $LicenseInfo:firstyear=2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2011, 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$
+*/
+
+#ifndef LL_LLCHICLETBAR_H
+#define LL_LLCHICLETBAR_H
+
+#include "llpanel.h"
+#include "llimview.h"
+
+class LLChicletPanel;
+class LLIMChiclet;
+class LLLayoutPanel;
+class LLLayoutStack;
+
+class LLChicletBar
+	: public LLSingleton<LLChicletBar>
+	, public LLPanel
+	, public LLIMSessionObserver
+{
+	LOG_CLASS(LLChicletBar);
+	friend class LLSingleton<LLChicletBar>;
+public:
+	~LLChicletBar();
+
+	BOOL postBuild();
+
+	LLChicletPanel*	getChicletPanel() { return mChicletPanel; }
+
+	// LLIMSessionObserver observe triggers
+	virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+	virtual void sessionRemoved(const LLUUID& session_id);
+	void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
+
+	S32 getTotalUnreadIMCount();
+
+	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
+
+	/**
+	 * Creates IM Chiclet based on session type (IM chat or Group chat)
+	 */
+	LLIMChiclet* createIMChiclet(const LLUUID& session_id);
+
+	/**
+	 * Shows/hides panel with specified well button (IM or Notification)
+	 *
+	 * @param well_name - name of the well panel to be processed.
+	 * @param visible - a flag specifying whether a button should be shown or hidden.
+	 */
+	void showWellButton(const std::string& well_name, bool visible);
+
+private:
+	/**
+	 * Updates child controls size and visibility when it is necessary to reduce total width.
+	 *
+	 * @param delta_width - value by which chiclet bar should be shrunk. It is a negative value.
+	 * @returns positive value which chiclet bar can not process when it reaches its minimal width.
+	 *		Zero if there was enough space to process delta_width.
+	 */
+	S32 processWidthDecreased(S32 delta_width);
+
+	/** helper function to log debug messages */
+	void log(LLView* panel, const std::string& descr);
+
+	/**
+	 * @return difference between current chiclet panel width and the minimum.
+	 */
+	S32 getChicletPanelShrinkHeadroom() const;
+
+protected:
+	LLChicletBar(const LLSD& key = LLSD());
+
+	LLChicletPanel* 	mChicletPanel;
+	LLLayoutStack*		mToolbarStack;
+};
+
+#endif // LL_LLCHICLETBAR_H
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 14d85246e94..f5cda52d444 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -34,9 +34,9 @@
 #include "llappviewer.h"
 #include "llavatarnamecache.h"
 #include "llbutton.h"
-#include "llbottomtray.h"
 #include "llchannelmanager.h"
 #include "llchiclet.h"
+#include "llchicletbar.h"
 #include "llfloaterreg.h"
 #include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container
 #include "llinventoryfunctions.h"
@@ -117,14 +117,14 @@ void LLIMFloater::onFocusLost()
 {
 	LLIMModel::getInstance()->resetActiveSessionID();
 	
-	LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, false);
+	LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, false);
 }
 
 void LLIMFloater::onFocusReceived()
 {
 	LLIMModel::getInstance()->setActiveSessionID(mSessionID);
 
-	LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, true);
+	LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, true);
 
 	if (getVisible())
 	{
@@ -444,7 +444,7 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
 		if (floater->getDockControl() == NULL)
 		{
 			LLChiclet* chiclet =
-					LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLChiclet>(
+					LLChicletBar::getInstance()->getChicletPanel()->findChiclet<LLChiclet>(
 							session_id);
 			if (chiclet == NULL)
 			{
@@ -452,11 +452,11 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
 			}
 			else
 			{
-				LLBottomTray::getInstance()->getChicletPanel()->scrollToChiclet(chiclet);
+				LLChicletBar::getInstance()->getChicletPanel()->scrollToChiclet(chiclet);
 			}
 
 			floater->setDockControl(new LLDockControl(chiclet, floater, floater->getDockTongue(),
-					LLDockControl::TOP,  boost::bind(&LLIMFloater::getAllowedRect, floater, _1)));
+					LLDockControl::BOTTOM));
 		}
 
 		// window is positioned, now we can show it.
@@ -466,11 +466,6 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
 	return floater;
 }
 
-void LLIMFloater::getAllowedRect(LLRect& rect)
-{
-	rect = gViewerWindow->getWorldViewRectScaled();
-}
-
 void LLIMFloater::setDocked(bool docked, bool pop_on_undock)
 {
 	// update notification channel state
@@ -522,7 +517,7 @@ void LLIMFloater::setVisible(BOOL visible)
 
 	if(!visible)
 	{
-		LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(mSessionID);
+		LLIMChiclet* chiclet = LLChicletBar::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(mSessionID);
 		if(chiclet)
 		{
 			chiclet->setToggleState(false);
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index 8a3020ea10a..f7cd35b5eb2 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -145,8 +145,6 @@ class LLIMFloater : public LLTransientDockableFloater
 	static void*	createPanelIMControl(void* userdata);
 	static void*	createPanelGroupControl(void* userdata);
 	static void* 	createPanelAdHocControl(void* userdata);
-	// gets a rect that bounds possible positions for the LLIMFloater on a screen (EXT-1111)
-	void getAllowedRect(LLRect& rect);
 
 	// Add the "User is typing..." indicator.
 	void addTypingIndicator(const LLIMInfo* im_info);
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 46025337361..441ea2923d1 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -1675,11 +1675,6 @@ LLCallDialog::~LLCallDialog()
 	LLUI::removePopup(this);
 }
 
-void LLCallDialog::getAllowedRect(LLRect& rect)
-{
-	rect = gViewerWindow->getWorldViewRectScaled();
-}
-
 BOOL LLCallDialog::postBuild()
 {
 	if (!LLDockableFloater::postBuild())
@@ -1690,8 +1685,7 @@ BOOL LLCallDialog::postBuild()
 
 	setDockControl(new LLDockControl(
 		anchor_panel, this,
-		getDockTongue(), LLDockControl::TOP,
-		boost::bind(&LLCallDialog::getAllowedRect, this, _1)));
+		getDockTongue(), LLDockControl::TOP));
 
 	return TRUE;
 }
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index 0ee56c80704..93b604d36aa 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -508,8 +508,6 @@ class LLCallDialog : public LLDockableFloater
 	virtual bool lifetimeHasExpired();
 	virtual void onLifetimeExpired();
 
-	virtual void getAllowedRect(LLRect& rect);
-
 	/**
 	 * Sets icon depend on session.
 	 *
diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp
index 170e23e4c5d..85a7e752715 100644
--- a/indra/newview/llscriptfloater.cpp
+++ b/indra/newview/llscriptfloater.cpp
@@ -28,9 +28,9 @@
 #include "llscriptfloater.h"
 #include "llagentcamera.h"
 
-#include "llbottomtray.h"
 #include "llchannelmanager.h"
 #include "llchiclet.h"
+#include "llchicletbar.h"
 #include "llfloaterreg.h"
 #include "lllslconstants.h"
 #include "llnotifications.h"
@@ -95,7 +95,7 @@ bool LLScriptFloater::toggle(const LLUUID& notification_id)
 		show(notification_id);
 	}
 
-	LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(notification_id, true);
+	LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(notification_id, true);
 	return true;
 }
 
@@ -131,11 +131,6 @@ void LLScriptFloater::setNotificationId(const LLUUID& id)
 	mObjectId = notification_id_to_object_id(id);
 }
 
-void LLScriptFloater::getAllowedRect(LLRect& rect)
-{
-	rect = gViewerWindow->getWorldViewRectScaled();
-}
-
 void LLScriptFloater::createForm(const LLUUID& notification_id)
 {
 	// delete old form
@@ -211,7 +206,7 @@ void LLScriptFloater::setVisible(BOOL visible)
 
 	if(!visible)
 	{
-		LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(getNotificationId());
+		LLIMChiclet* chiclet = LLChicletBar::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(getNotificationId());
 		if(chiclet)
 		{
 			chiclet->setToggleState(false);
@@ -224,7 +219,7 @@ void LLScriptFloater::onMouseDown()
 	if(getNotificationId().notNull())
 	{
 		// Remove new message icon
-		LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(getNotificationId());
+		LLIMChiclet* chiclet = LLChicletBar::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(getNotificationId());
 		if (chiclet == NULL)
 		{
 			llerror("Dock chiclet for LLScriptFloater doesn't exist", 0);
@@ -267,7 +262,7 @@ void LLScriptFloater::onFocusLost()
 {
 	if(getNotificationId().notNull())
 	{
-		LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(getNotificationId(), false);
+		LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(getNotificationId(), false);
 	}
 }
 
@@ -276,7 +271,7 @@ void LLScriptFloater::onFocusReceived()
 	// first focus will be received before setObjectId() call - don't toggle chiclet
 	if(getNotificationId().notNull())
 	{
-		LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(getNotificationId(), true);
+		LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(getNotificationId(), true);
 	}
 }
 
@@ -284,7 +279,7 @@ void LLScriptFloater::dockToChiclet(bool dock)
 {
 	if (getDockControl() == NULL)
 	{
-		LLChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLChiclet>(getNotificationId());
+		LLChiclet* chiclet = LLChicletBar::getInstance()->getChicletPanel()->findChiclet<LLChiclet>(getNotificationId());
 		if (chiclet == NULL)
 		{
 			llwarns << "Dock chiclet for LLScriptFloater doesn't exist" << llendl;
@@ -292,7 +287,7 @@ void LLScriptFloater::dockToChiclet(bool dock)
 		}
 		else
 		{
-			LLBottomTray::getInstance()->getChicletPanel()->scrollToChiclet(chiclet);
+			LLChicletBar::getInstance()->getChicletPanel()->scrollToChiclet(chiclet);
 		}
 
 		// Stop saving position while we dock floater
@@ -300,7 +295,7 @@ void LLScriptFloater::dockToChiclet(bool dock)
 		setSavePosition(false);
 
 		setDockControl(new LLDockControl(chiclet, this, getDockTongue(),
-			LLDockControl::TOP,  boost::bind(&LLScriptFloater::getAllowedRect, this, _1)));
+			LLDockControl::BOTTOM));
 
 		setDocked(dock);
 
@@ -352,7 +347,7 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)
 		script_notification_map_t::const_iterator it = findUsingObjectId(object_id);
 		if(it != mNotifications.end())
 		{
-			LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(it->first);
+			LLIMChiclet* chiclet = LLChicletBar::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(it->first);
 			if(chiclet)
 			{
 				// Pass the new_message icon state further.
@@ -375,11 +370,11 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)
 	// Create inventory offer chiclet for offer type notifications
 	if( OBJ_GIVE_INVENTORY == obj_type )
 	{
-		LLBottomTray::instance().getChicletPanel()->createChiclet<LLInvOfferChiclet>(notification_id);
+		LLChicletBar::instance().getChicletPanel()->createChiclet<LLInvOfferChiclet>(notification_id);
 	}
 	else
 	{
-		LLBottomTray::getInstance()->getChicletPanel()->createChiclet<LLScriptChiclet>(notification_id);
+		LLChicletBar::getInstance()->getChicletPanel()->createChiclet<LLScriptChiclet>(notification_id);
 	}
 
 	LLIMWellWindow::getInstance()->addObjectRow(notification_id, set_new_message);
@@ -413,7 +408,7 @@ void LLScriptFloaterManager::onRemoveNotification(const LLUUID& notification_id)
 	}
 
 	// remove related chiclet
-	LLBottomTray::getInstance()->getChicletPanel()->removeChiclet(notification_id);
+	LLChicletBar::getInstance()->getChicletPanel()->removeChiclet(notification_id);
 
 	LLIMWellWindow::getInstance()->removeObjectRow(notification_id);
 
diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h
index 8e959a3d0e2..70451194b38 100644
--- a/indra/newview/llscriptfloater.h
+++ b/indra/newview/llscriptfloater.h
@@ -185,8 +185,6 @@ class LLScriptFloater : public LLDockableFloater
 	 */
 	void createForm(const LLUUID& object_id);
 
-	/*virtual*/ void getAllowedRect(LLRect& rect);
-
 	/**
 	 * Hide all notification toasts.
 	 */
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index cb49976e5f5..ffe864e2207 100644
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -35,16 +35,17 @@
 #include "llfloaterreg.h"
 #include "llnotifications.h"
 
-#include "llbottomtray.h"
 #include "llscriptfloater.h"
 #include "llviewercontrol.h"
 #include "llviewerwindow.h"
 
 #include "llchiclet.h"
+#include "llchicletbar.h"
 #include "lltoastpanel.h"
 #include "llnotificationmanager.h"
 #include "llnotificationsutil.h"
 #include "llspeakers.h"
+#include "lltoolbarview.h"
 
 //---------------------------------------------------------------------------------
 LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLTransientDockableFloater(NULL, true,  key),
@@ -139,15 +140,6 @@ void LLSysWellWindow::initChannel()
 	}
 }
 
-//---------------------------------------------------------------------------------
-void LLSysWellWindow::getAllowedRect(LLRect& rect)
-{
-	rect = gViewerWindow->getWorldViewRectScaled();
-}
-
-//---------------------------------------------------------------------------------
-
-
 //---------------------------------------------------------------------------------
 void LLSysWellWindow::setVisible(BOOL visible)
 {
@@ -156,8 +148,8 @@ void LLSysWellWindow::setVisible(BOOL visible)
 		if (NULL == getDockControl() && getDockTongue().notNull())
 		{
 			setDockControl(new LLDockControl(
-				LLBottomTray::getInstance()->getChild<LLView>(getAnchorViewName()), this,
-				getDockTongue(), LLDockControl::TOP, boost::bind(&LLSysWellWindow::getAllowedRect, this, _1)));
+				LLChicletBar::getInstance()->getChild<LLView>(getAnchorViewName()), this,
+				getDockTongue(), LLDockControl::BOTTOM));
 		}
 	}
 
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 9f8ab018108..52e53705059 100644
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -76,11 +76,6 @@ class LLSysWellWindow : public LLTransientDockableFloater
 	static const S32 MIN_WINDOW_WIDTH		= 318;
 
 protected:
-
-	// gets a rect that bounds possible positions for the SysWellWindow on a screen (EXT-1111)
-	void getAllowedRect(LLRect& rect);
-
-
 	// init Window's channel
 	virtual void initChannel();
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 665b31a427e..85f74c9fdd5 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -84,6 +84,7 @@
 // newview includes
 #include "llagent.h"
 #include "llbox.h"
+#include "llchicletbar.h"
 #include "llconsole.h"
 #include "llviewercontrol.h"
 #include "llcylinder.h"
@@ -1848,13 +1849,12 @@ void LLViewerWindow::initWorldUI()
 	//getRootView()->sendChildToFront(gFloaterView);
 	//getRootView()->sendChildToFront(gSnapshotFloaterView);
 
-	// new bottom panel
-	LLPanel* bottom_tray_container = getRootView()->getChild<LLPanel>("bottom_tray_container");
-	LLBottomTray* bottom_tray = LLBottomTray::getInstance();
-	bottom_tray->setShape(bottom_tray_container->getLocalRect());
-	bottom_tray->setFollowsAll();
-	bottom_tray_container->addChild(bottom_tray);
-	bottom_tray_container->setVisible(TRUE);
+	LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container");
+	LLChicletBar* chiclet_bar = LLChicletBar::getInstance();
+	chiclet_bar->setShape(chiclet_container->getLocalRect());
+	chiclet_bar->setFollowsAll();
+	chiclet_container->addChild(chiclet_bar);
+	chiclet_container->setVisible(TRUE);
 
 	LLRect morph_view_rect = full_window;
 	morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
diff --git a/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml b/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml
new file mode 100644
index 00000000000..355a76e05f9
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_chiclet_bar.xml
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="false"
+ chrome="true"
+ follows="left|top|right"
+ height="30"
+ layout="topleft"
+ mouse_opaque="false"
+ name="chiclet_bar"
+ width="1310">
+  <layout_stack
+     border_size="0"
+     clip="false"
+     follows="all"
+     height="30"
+     layout="topleft"
+     left="0"
+     mouse_opaque="false"
+     name="toolbar_stack"
+     orientation="horizontal"
+     top="0"
+     width="1310">
+        <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">
+      <chiclet_panel
+             chiclet_padding="4"
+             follows="left|right"
+             height="24"
+             layout="topleft"
+             left="1"
+             min_width="95"
+             mouse_opaque="false"
+             name="chiclet_list"
+             top="7"
+             width="189">
+        <button
+                 auto_resize="true"
+                 follows="right"
+                 height="29"
+                 image_hover_selected="SegmentedBtn_Left_Over"
+                 image_hover_unselected="SegmentedBtn_Left_Over"
+                 image_overlay="Arrow_Small_Left"
+                 image_pressed="SegmentedBtn_Left_Press"
+                 image_pressed_selected="SegmentedBtn_Left_Press"
+                 image_selected="SegmentedBtn_Left_Off"
+                 image_unselected="SegmentedBtn_Left_Off"
+                 layout="topleft"
+                 name="chicklet_left_scroll_button"
+                 tab_stop="false"
+                 top="-28"
+                 visible="false"
+                 width="7" />
+        <button
+                 auto_resize="true"
+                 follows="right"
+                 height="29"
+                 image_hover_selected="SegmentedBtn_Right_Over"
+                 image_hover_unselected="SegmentedBtn_Right_Over"
+                 image_overlay="Arrow_Small_Right"
+                 image_pressed="SegmentedBtn_Right_Press"
+                 image_pressed_selected="SegmentedBtn_Right_Press"
+                 image_selected="SegmentedBtn_Right_Off"
+                 image_unselected="SegmentedBtn_Right_Off"
+                 layout="topleft"
+                 name="chicklet_right_scroll_button"
+                 tab_stop="false"
+                 top="-28"
+                 visible="false"
+                 width="7" />
+      </chiclet_panel>
+    </layout_panel>
+    <layout_panel auto_resize="false"
+                      user_resize="false"
+                      width="4"
+                      min_width="4"/>
+    <layout_panel
+         auto_resize="false"
+         follows="right"
+         height="28"
+         layout="topleft"
+         min_height="28"
+         min_width="37"
+         name="im_well_panel"
+         top="0"
+         user_resize="false"
+         width="37">
+      <chiclet_im_well
+             follows="right"
+             height="28"
+             layout="topleft"
+             left="0"
+             max_displayed_count="99"
+             name="im_well"
+             top="0"
+             width="35">
+        <!--
+Emulate 4 states of button by background images, see details in EXT-3147. The same should be for notification_well button
+xml attribute           Description
+image_unselected        "Unlit" - there are no new messages
+image_selected          "Unlit" + "Selected" - there are no new messages and the Well is open
+image_pressed           "Lit" - there are new messages
+image_pressed_selected  "Lit" + "Selected" - there are new messages and the Well is open
+             -->
+        <button
+                 auto_resize="true"
+                 follows="right"
+                 halign="center"
+                 height="23"
+                 image_overlay="Unread_IM"
+                 image_overlay_alignment="center"
+                 image_pressed="WellButton_Lit"
+                 image_pressed_selected="WellButton_Lit_Selected"
+                 image_selected="PushButton_Press"
+                 label_color="Black"
+                 left="0"
+                 name="Unread IM messages"
+                 tool_tip="Conversations"
+                 width="34">
+          <init_callback
+                     function="Button.SetDockableFloaterToggle"
+                     parameter="im_well_window" />
+        </button>
+      </chiclet_im_well>
+    </layout_panel>
+    <layout_panel
+         auto_resize="false"
+         follows="right"
+         height="28"
+         layout="topleft"
+         min_height="28"
+         min_width="37"
+         name="notification_well_panel"
+         top="0"
+         user_resize="false"
+         width="37">
+      <chiclet_notification
+             follows="right"
+             height="23"
+             layout="topleft"
+             left="0"
+             max_displayed_count="99"
+             name="notification_well"
+             top="5"
+             width="35">
+        <button
+                 auto_resize="true"
+                 bottom_pad="3"
+                 follows="right"
+                 halign="center"
+                 height="23"
+                 image_overlay="Notices_Unread"
+                 image_overlay_alignment="center"
+                 image_pressed="WellButton_Lit"
+                 image_pressed_selected="WellButton_Lit_Selected"
+                 image_selected="PushButton_Press"
+                 label_color="Black"
+                 left="0"
+                 name="Unread"
+                 tool_tip="Notifications"
+                 width="34">
+          <init_callback
+                     function="Button.SetDockableFloaterToggle"
+                     parameter="notification_well_window" />
+        </button>
+      </chiclet_notification>
+    </layout_panel>
+  </layout_stack>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_toolbar_view.xml b/indra/newview/skins/default/xui/en/panel_toolbar_view.xml
index 5475fcd2454..3c69a0cb6cc 100644
--- a/indra/newview/skins/default/xui/en/panel_toolbar_view.xml
+++ b/indra/newview/skins/default/xui/en/panel_toolbar_view.xml
@@ -64,14 +64,32 @@
                     user_resize="false"
                     mouse_opaque="false"
                     height="100"
-                    width="100">
+                    width="200">
         <view top="0"
               follows="all"
               height="100"
               left="0"
               mouse_opaque="false"
               name="floater_snap_region"
-              width="100"/>
+              width="200"/>
+        <view top="0"
+              follows="left|top|bottom"
+              height="100"
+              left="0"
+              mouse_opaque="false"
+              name="minimized_floaters_region"
+              width="160"/>
+        <panel follows="left|top|right"
+               layout="topleft"
+               height="30"
+               left_pad="10"
+               mouse_opaque="false"
+               name="chiclet_container"
+               tab_stop="false"
+               top="0"
+               bg_visible="false"
+               width="20">
+        </panel>          
         <panel bottom="100"
                follows="left|right|bottom"
                height="25"
@@ -80,7 +98,7 @@
                tab_stop="false"
                name="stand_stop_flying_container"
                visible="false"
-               width="100"/>
+               width="200"/>
       </layout_panel>
       <layout_panel name="right_toolbar_panel"
                     auto_resize="false"
-- 
GitLab