From 8d6e7fa02c0d5cd18f91ac6862079ff4fa0719d4 Mon Sep 17 00:00:00 2001
From: Leslie Linden <leslie@lindenlab.com>
Date: Mon, 24 Oct 2011 16:49:00 -0700
Subject: [PATCH] * Fixed destination guide floater to display on login based
 on per account   "DisplayDestinationsOnInitialRun" setting or initial agent
 SL login. * Added toolbar enumeration for toolbar view so queries for
 commands can now   indicate where the command currently is on the left, right
 or bottom toolbars. * Updated toybox toolbar button tooltips to indicate
 where the command currently   resides in the view. * Added unused function to
 allow toolbar buttons to be changed to flash   indefinitely.

Reviewed by Richard.
---
 indra/llui/lltoolbar.cpp                      |  61 ++--
 indra/llui/lltoolbar.h                        |  19 +-
 .../app_settings/settings_per_account.xml     |  11 +
 indra/newview/llfloatertoybox.cpp             |  30 +-
 indra/newview/llfloatertoybox.h               |   2 +
 indra/newview/lltoolbarview.cpp               | 264 +++++++++++-------
 indra/newview/lltoolbarview.h                 |  36 ++-
 .../newview/skins/default/xui/en/strings.xml  |   6 +-
 .../skins/default/xui/en/widgets/toolbar.xml  |   4 +
 9 files changed, 295 insertions(+), 138 deletions(-)

diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index b0a072c00e0..97dc1e33166 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -113,6 +113,7 @@ LLToolBar::LLToolBar(const LLToolBar::Params& p)
 	mHandleDragItemCallback(NULL),
 	mHandleDropCallback(NULL),
 	mButtonAddSignal(NULL),
+	mButtonEnterSignal(NULL),
 	mDragAndDropTarget(false)
 {
 	mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text;
@@ -123,6 +124,7 @@ LLToolBar::~LLToolBar()
 {
 	delete mPopupMenuHandle.get();
 	delete mButtonAddSignal;
+	delete mButtonEnterSignal;
 }
 
 void LLToolBar::createContextMenu()
@@ -358,6 +360,23 @@ bool LLToolBar::stopCommandInProgress(const LLCommandId& commandId)
 	return (command_button != NULL);
 }
 
+bool LLToolBar::flashCommand(const LLCommandId& commandId, bool flash)
+{
+	LLButton * command_button = NULL;
+
+	if (commandId != LLCommandId::null)
+	{
+		command_id_map::iterator it = mButtonMap.find(commandId.uuid());
+		if (it != mButtonMap.end())
+		{
+			command_button = it->second;
+			command_button->setFlashing(flash ? TRUE : FALSE);
+		}
+	}
+
+	return (command_button != NULL);
+}
+
 BOOL LLToolBar::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
 	LLRect button_panel_rect;
@@ -876,8 +895,7 @@ LLToolBarButton* LLToolBar::createButton(const LLCommandId& id)
 			button->setCommitCallback(executeParam);
 		}
 
-
-
+		// Set up "is running" query callback
 		const std::string& isRunningFunction = commandp->isRunningFunctionName();
 		if (isRunningFunction.length() > 0)
 		{
@@ -904,12 +922,18 @@ LLToolBarButton* LLToolBar::createButton(const LLCommandId& id)
 	return button;
 }
 
-boost::signals2::connection LLToolBar::setButtonAddCallback(const button_add_signal_t::slot_type& cb)
+boost::signals2::connection LLToolBar::setButtonAddCallback(const button_signal_t::slot_type& cb)
 {
-	if (!mButtonAddSignal) mButtonAddSignal = new button_add_signal_t();
+	if (!mButtonAddSignal) mButtonAddSignal = new button_signal_t();
 	return mButtonAddSignal->connect(cb);
 }
 
+boost::signals2::connection LLToolBar::setButtonEnterCallback(const button_signal_t::slot_type& cb)
+{
+	if (!mButtonEnterSignal) mButtonEnterSignal = new button_signal_t();
+	return mButtonEnterSignal->connect(cb);
+}
+
 BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 										EDragAndDropType cargo_type,
 										void* cargo_data,
@@ -981,8 +1005,6 @@ LLToolBarButton::LLToolBarButton(const Params& p)
 	mOriginalImageOverlayColor(p.image_overlay_color),
 	mOriginalImageOverlaySelectedColor(p.image_overlay_selected_color)
 {
-	mButtonFlashRate = 0.0;
-	mButtonFlashCount = 0;
 }
 
 LLToolBarButton::~LLToolBarButton()
@@ -1024,6 +1046,7 @@ BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask)
 	{
 		handled = LLButton::handleHover(x, y, mask);
 	}
+
 	return handled;
 }
 
@@ -1036,6 +1059,12 @@ void LLToolBarButton::onMouseEnter(S32 x, S32 y, MASK mask)
 	{
 		mNeedsHighlight = TRUE;
 	}
+
+	LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+	if (parent_toolbar && parent_toolbar->mButtonEnterSignal)
+	{
+		(*(parent_toolbar->mButtonEnterSignal))(this);
+	}
 }
 
 void LLToolBarButton::onMouseCaptureLost()
@@ -1084,25 +1113,25 @@ void LLToolBarButton::setEnabled(BOOL enabled)
 	}
 }
 
-
 const std::string LLToolBarButton::getToolTip() const	
 { 
 	std::string tooltip;
+
 	if (labelIsTruncated() || getCurrentLabel().empty())
 	{
-		return LLTrans::getString(LLCommandManager::instance().getCommand(mId)->labelRef()) + " -- " + LLView::getToolTip();
+		tooltip = LLTrans::getString(LLCommandManager::instance().getCommand(mId)->labelRef()) + " -- " + LLView::getToolTip();
 	}
 	else
 	{
-		return LLView::getToolTip();
+		tooltip = LLView::getToolTip();
 	}
-}
-
-
-
-
-
-
 
+	LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+	if (parent_toolbar && parent_toolbar->mButtonTooltipSuffix.length() > 0)
+	{
+		tooltip = tooltip + "\n(" + parent_toolbar->mButtonTooltipSuffix + ")";
+	}
 
+	return tooltip;
+}
 
diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h
index 68fc44ee8ee..7ceb75aeedb 100644
--- a/indra/llui/lltoolbar.h
+++ b/indra/llui/lltoolbar.h
@@ -120,6 +120,8 @@ namespace LLToolBarEnums
 		SIDE_RIGHT,
 		SIDE_TOP,
 	};
+
+	LLLayoutStack::ELayoutOrientation getOrientation(SideType sideType);
 }
 
 // NOTE: This needs to occur before Param block declaration for proper compilation.
@@ -142,6 +144,7 @@ namespace LLInitParam
 class LLToolBar
 :	public LLUICtrl
 {
+	friend class LLToolBarButton;
 public:
 	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
 	{
@@ -187,6 +190,7 @@ class LLToolBar
 	bool hasCommand(const LLCommandId& commandId) const;
 	bool enableCommand(const LLCommandId& commandId, bool enabled);
 	bool stopCommandInProgress(const LLCommandId& commandId);
+	bool flashCommand(const LLCommandId& commandId, bool flash);
 
 	void setStartDragCallback(tool_startdrag_callback_t cb)   { mStartDragItemCallback  = cb; }
 	void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; }
@@ -195,9 +199,13 @@ class LLToolBar
 
 	LLToolBarButton* createButton(const LLCommandId& id);
 
-	typedef boost::signals2::signal<void (LLView* button)> button_add_signal_t;
-	boost::signals2::connection setButtonAddCallback(const button_add_signal_t::slot_type& cb);
+	typedef boost::signals2::signal<void (LLView* button)> button_signal_t;
+	boost::signals2::connection setButtonAddCallback(const button_signal_t::slot_type& cb);
+	boost::signals2::connection setButtonEnterCallback(const button_signal_t::slot_type& cb);
+
+	void setTooltipButtonSuffix(const std::string& suffix) { mButtonTooltipSuffix = suffix; }
 
+	LLToolBarEnums::SideType getSideType() const { return mSideType; }
 	bool hasButtons() const { return !mButtons.empty(); }
 	bool isModified() const { return mModified; }
 
@@ -257,9 +265,12 @@ class LLToolBar
 
 	LLToolBarButton::Params			mButtonParams[LLToolBarEnums::BTNTYPE_COUNT];
 
-	LLHandle<class LLContextMenu>			mPopupMenuHandle;
+	LLHandle<class LLContextMenu>	mPopupMenuHandle;
+
+	button_signal_t*				mButtonAddSignal;
+	button_signal_t*				mButtonEnterSignal;
 
-	button_add_signal_t*			mButtonAddSignal;
+	std::string						mButtonTooltipSuffix;
 };
 
 
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index d8295ddb876..6ed4480cb19 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -33,6 +33,17 @@
         <key>Value</key>
             <string />
         </map>
+    <key>DisplayDestinationsOnInitialRun</key>
+        <map>
+        <key>Comment</key>
+          <string>Display the destinations guide when a user first launches FUI.</string>
+        <key>Persist</key>
+          <integer>1</integer>
+        <key>Type</key>
+          <string>Boolean</string>
+        <key>Value</key>
+          <integer>1</integer>
+        </map>
     <key>LastInventoryInboxActivity</key>
         <map>
         <key>Comment</key>
diff --git a/indra/newview/llfloatertoybox.cpp b/indra/newview/llfloatertoybox.cpp
index 66f644748ea..f527937e8f5 100644
--- a/indra/newview/llfloatertoybox.cpp
+++ b/indra/newview/llfloatertoybox.cpp
@@ -63,6 +63,7 @@ BOOL LLFloaterToybox::postBuild()
 	mToolBar->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
 	mToolBar->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
 	mToolBar->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
+	mToolBar->setButtonEnterCallback(boost::bind(&LLFloaterToybox::onToolBarButtonEnter,this,_1));
 	
 	//
 	// Sort commands by localized labels so they will appear alphabetized in all languages
@@ -105,8 +106,8 @@ void LLFloaterToybox::draw()
 	{
 		const LLCommandId& id = *it;
 
-		const bool commandOnToolbar = gToolBarView->hasCommand(id);
-		mToolBar->enableCommand(id, !commandOnToolbar);
+		const bool command_not_present = (gToolBarView->hasCommand(id) == LLToolBarView::TOOLBAR_NONE);
+		mToolBar->enableCommand(id, command_not_present);
 	}
 
 	LLFloater::draw();
@@ -140,5 +141,30 @@ BOOL LLFloaterToybox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 	return mToolBar->handleDragAndDrop(local_x, local_y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
 }
 
+void LLFloaterToybox::onToolBarButtonEnter(LLView* button)
+{
+	std::string suffix = "";
+
+	LLCommandId commandId(button->getName());
+	LLCommand* command = LLCommandManager::instance().getCommand(commandId);
+
+	if (command)
+	{
+		S32 command_loc = gToolBarView->hasCommand(commandId);
+
+		switch(command_loc)
+		{
+		case LLToolBarView::TOOLBAR_BOTTOM:	suffix = LLTrans::getString("Toolbar_Bottom_Tooltip");	break;
+		case LLToolBarView::TOOLBAR_LEFT:	suffix = LLTrans::getString("Toolbar_Left_Tooltip");	break;
+		case LLToolBarView::TOOLBAR_RIGHT:	suffix = LLTrans::getString("Toolbar_Right_Tooltip");	break;
+
+		default:
+			break;
+		}
+	}
+
+	mToolBar->setTooltipButtonSuffix(suffix);
+}
+
 
 // eof
diff --git a/indra/newview/llfloatertoybox.h b/indra/newview/llfloatertoybox.h
index 62bf68680da..6f0275b8fe2 100644
--- a/indra/newview/llfloatertoybox.h
+++ b/indra/newview/llfloatertoybox.h
@@ -52,6 +52,8 @@ class LLFloaterToybox : public LLFloater
 protected:
 	void onBtnRestoreDefaults();
 
+	void onToolBarButtonEnter(LLView* button);
+
 public:
 	LLToolBar *	mToolBar;
 };
diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp
index 9eea49914f3..8f4f7d405fc 100644
--- a/indra/newview/lltoolbarview.cpp
+++ b/indra/newview/lltoolbarview.cpp
@@ -69,13 +69,14 @@ LLToolBarView::ToolbarSet::ToolbarSet()
 
 LLToolBarView::LLToolBarView(const LLToolBarView::Params& p)
 :	LLUICtrl(p),
-	mToolbarLeft(NULL),
-	mToolbarRight(NULL),
-	mToolbarBottom(NULL),
 	mDragStarted(false),
 	mDragToolbarButton(NULL),
 	mToolbarsLoaded(false)
 {
+	for (S32 i = 0; i < TOOLBAR_COUNT; i++)
+	{
+		mToolbars[i] = NULL;
+	}
 }
 
 void LLToolBarView::initFromParams(const LLToolBarView::Params& p)
@@ -91,49 +92,99 @@ LLToolBarView::~LLToolBarView()
 
 BOOL LLToolBarView::postBuild()
 {
-	mToolbarLeft   = getChild<LLToolBar>("toolbar_left");
-	mToolbarRight  = getChild<LLToolBar>("toolbar_right");
-	mToolbarBottom = getChild<LLToolBar>("toolbar_bottom");
-
-	mToolbarLeft->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
-	mToolbarLeft->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
-	mToolbarLeft->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
-	mToolbarLeft->setButtonAddCallback(boost::bind(LLToolBarView::onToolBarButtonAdded, _1));
-	
-	mToolbarRight->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
-	mToolbarRight->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
-	mToolbarRight->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
-	mToolbarRight->setButtonAddCallback(boost::bind(LLToolBarView::onToolBarButtonAdded, _1));
-	
-	mToolbarBottom->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
-	mToolbarBottom->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
-	mToolbarBottom->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
-	mToolbarBottom->setButtonAddCallback(boost::bind(LLToolBarView::onToolBarButtonAdded, _1));
+	mToolbars[TOOLBAR_LEFT]   = getChild<LLToolBar>("toolbar_left");
+	mToolbars[TOOLBAR_RIGHT]  = getChild<LLToolBar>("toolbar_right");
+	mToolbars[TOOLBAR_BOTTOM] = getChild<LLToolBar>("toolbar_bottom");
+
+	for (int i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+	{
+		mToolbars[i]->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
+		mToolbars[i]->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
+		mToolbars[i]->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
+		mToolbars[i]->setButtonAddCallback(boost::bind(LLToolBarView::onToolBarButtonAdded,_1));
+	}
 
 	LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&handleLoginToolbarSetup));
 	
 	return TRUE;
 }
 
-bool LLToolBarView::hasCommand(const LLCommandId& commandId) const
+S32 LLToolBarView::hasCommand(const LLCommandId& commandId) const
 {
-	bool has_command = false;
-	if (mToolbarLeft && !has_command)
+	S32 command_location = TOOLBAR_NONE;
+
+	for (S32 loc = TOOLBAR_FIRST; loc <= TOOLBAR_LAST; loc++)
 	{
-		has_command = mToolbarLeft->hasCommand(commandId);
+		if (mToolbars[loc]->hasCommand(commandId))
+		{
+			command_location = loc;
+			break;
+		}
 	}
-	if (mToolbarRight && !has_command)
+
+	return command_location;
+}
+
+S32 LLToolBarView::addCommand(const LLCommandId& commandId, EToolBarLocation toolbar, int rank)
+{
+	int old_rank;
+	removeCommand(commandId, old_rank);
+
+	S32 command_location = mToolbars[toolbar]->addCommand(commandId, rank);
+
+	return command_location;
+}
+
+S32 LLToolBarView::removeCommand(const LLCommandId& commandId, int& rank)
+{
+	S32 command_location = hasCommand(commandId);
+	rank = LLToolBar::RANK_NONE;
+
+	if (command_location != TOOLBAR_NONE)
+	{
+		rank = mToolbars[command_location]->removeCommand(commandId);
+	}
+
+	return command_location;
+}
+
+S32 LLToolBarView::enableCommand(const LLCommandId& commandId, bool enabled)
+{
+	S32 command_location = hasCommand(commandId);
+
+	if (command_location != TOOLBAR_NONE)
 	{
-		has_command = mToolbarRight->hasCommand(commandId);
+		mToolbars[command_location]->enableCommand(commandId, enabled);
 	}
-	if (mToolbarBottom && !has_command)
+
+	return command_location;
+}
+
+S32 LLToolBarView::stopCommandInProgress(const LLCommandId& commandId)
+{
+	S32 command_location = hasCommand(commandId);
+
+	if (command_location != TOOLBAR_NONE)
+	{
+		mToolbars[command_location]->stopCommandInProgress(commandId);
+	}
+
+	return command_location;
+}
+
+S32 LLToolBarView::flashCommand(const LLCommandId& commandId, bool flash)
+{
+	S32 command_location = hasCommand(commandId);
+
+	if (command_location != TOOLBAR_NONE)
 	{
-		has_command = mToolbarBottom->hasCommand(commandId);
+		mToolbars[command_location]->flashCommand(commandId, flash);
 	}
-	return has_command;
+
+	return command_location;
 }
 
-bool LLToolBarView::addCommand(const LLCommandId& command, LLToolBar* toolbar)
+bool LLToolBarView::addCommandInternal(const LLCommandId& command, LLToolBar* toolbar)
 {
 	LLCommandManager& mgr = LLCommandManager::instance();
 	if (mgr.getCommand(command))
@@ -166,7 +217,7 @@ bool LLToolBarView::loadToolbars(bool force_default)
 	}
 	
 	LLXMLNodePtr root;
-	if (!LLXMLNode::parseFile(toolbar_file, root, NULL))
+	if(!LLXMLNode::parseFile(toolbar_file, root, NULL))
 	{
 		llwarns << "Unable to load toolbars from file: " << toolbar_file << llendl;
 		err = true;
@@ -182,7 +233,7 @@ bool LLToolBarView::loadToolbars(bool force_default)
 	LLXUIParser parser;
 	if (!err)
 	{
-		parser.readXUI(root, toolbar_set, toolbar_file);
+	parser.readXUI(root, toolbar_set, toolbar_file);
 	}
 	if (!err && !toolbar_set.validateBlock())
 	{
@@ -195,69 +246,64 @@ bool LLToolBarView::loadToolbars(bool force_default)
 		if (force_default)
 		{
 			llerrs << "Unable to load toolbars from default file : " << toolbar_file << llendl;
-			return false;
-		}
+		return false;
+	}
 		// Try to load the default toolbars
 		return loadToolbars(true);
 	}
 	
 	// Clear the toolbars now before adding the loaded commands and settings
-	if (mToolbarLeft)
-	{
-		mToolbarLeft->clearCommandsList();
-	}
-	if (mToolbarRight)
-	{
-		mToolbarRight->clearCommandsList();
-	}
-	if (mToolbarBottom)
+	for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
 	{
-		mToolbarBottom->clearCommandsList();
+		if (mToolbars[i])
+		{
+			mToolbars[i]->clearCommandsList();
+		}
 	}
 	
 	// Add commands to each toolbar
-	if (toolbar_set.left_toolbar.isProvided() && mToolbarLeft)
+	if (toolbar_set.left_toolbar.isProvided() && mToolbars[TOOLBAR_LEFT])
 	{
 		if (toolbar_set.left_toolbar.button_display_mode.isProvided())
 		{
 			LLToolBarEnums::ButtonType button_type = toolbar_set.left_toolbar.button_display_mode;
-			mToolbarLeft->setButtonType(button_type);
+			mToolbars[TOOLBAR_LEFT]->setButtonType(button_type);
 		}
-		BOOST_FOREACH(const LLCommandId::Params& command_name_param, toolbar_set.left_toolbar.commands)
+		BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.left_toolbar.commands)
 		{
-			if (addCommand(LLCommandId(command_name_param), mToolbarLeft) == false)
+			if (addCommandInternal(LLCommandId(command_params), mToolbars[TOOLBAR_LEFT]))
 			{
-				llwarns << "Error adding command '" << command_name_param.name() << "' to left toolbar." << llendl;
+				llwarns << "Error adding command '" << command_params.name() << "' to left toolbar." << llendl;
 			}
 		}
 	}
-	if (toolbar_set.right_toolbar.isProvided() && mToolbarRight)
+	if (toolbar_set.right_toolbar.isProvided() && mToolbars[TOOLBAR_RIGHT])
 	{
 		if (toolbar_set.right_toolbar.button_display_mode.isProvided())
 		{
 			LLToolBarEnums::ButtonType button_type = toolbar_set.right_toolbar.button_display_mode;
-			mToolbarRight->setButtonType(button_type);
+			mToolbars[TOOLBAR_RIGHT]->setButtonType(button_type);
 		}
-		BOOST_FOREACH(const LLCommandId::Params& command_name_param, toolbar_set.right_toolbar.commands)
+		BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.right_toolbar.commands)
 		{
-			if (addCommand(LLCommandId(command_name_param), mToolbarRight) == false)
+			if (addCommandInternal(LLCommandId(command_params), mToolbars[TOOLBAR_RIGHT]))
 			{
-				llwarns << "Error adding command '" << command_name_param.name() << "' to right toolbar." << llendl;
+				llwarns << "Error adding command '" << command_params.name() << "' to right toolbar." << llendl;
 			}
 		}
 	}
-	if (toolbar_set.bottom_toolbar.isProvided() && mToolbarBottom)
+	if (toolbar_set.bottom_toolbar.isProvided() && mToolbars[TOOLBAR_BOTTOM])
 	{
 		if (toolbar_set.bottom_toolbar.button_display_mode.isProvided())
 		{
 			LLToolBarEnums::ButtonType button_type = toolbar_set.bottom_toolbar.button_display_mode;
-			mToolbarBottom->setButtonType(button_type);
+			mToolbars[TOOLBAR_BOTTOM]->setButtonType(button_type);
 		}
-		BOOST_FOREACH(const LLCommandId::Params& command_name_param, toolbar_set.bottom_toolbar.commands)
+		BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.bottom_toolbar.commands)
 		{
-			if (addCommand(LLCommandId(command_name_param), mToolbarBottom) == false)
+			if (addCommandInternal(LLCommandId(command_params), mToolbars[TOOLBAR_BOTTOM]))
 			{
-				llwarns << "Error adding command '" << command_name_param.name() << "' to bottom toolbar." << llendl;
+				llwarns << "Error adding command '" << command_params.name() << "' to bottom toolbar." << llendl;
 			}
 		}
 	}
@@ -289,20 +335,20 @@ void LLToolBarView::saveToolbars() const
 	
 	// Build the parameter tree from the toolbar data
 	LLToolBarView::ToolbarSet toolbar_set;
-	if (mToolbarLeft)
+	if (mToolbars[TOOLBAR_LEFT])
 	{
-		toolbar_set.left_toolbar.button_display_mode = mToolbarLeft->getButtonType();
-		addToToolset(mToolbarLeft->getCommandsList(),toolbar_set.left_toolbar);
+		toolbar_set.left_toolbar.button_display_mode = mToolbars[TOOLBAR_LEFT]->getButtonType();
+		addToToolset(mToolbars[TOOLBAR_LEFT]->getCommandsList(), toolbar_set.left_toolbar);
 	}
-	if (mToolbarRight)
+	if (mToolbars[TOOLBAR_RIGHT])
 	{
-		toolbar_set.right_toolbar.button_display_mode = mToolbarRight->getButtonType();
-		addToToolset(mToolbarRight->getCommandsList(),toolbar_set.right_toolbar);
+		toolbar_set.right_toolbar.button_display_mode = mToolbars[TOOLBAR_RIGHT]->getButtonType();
+		addToToolset(mToolbars[TOOLBAR_RIGHT]->getCommandsList(), toolbar_set.right_toolbar);
 	}
-	if (mToolbarBottom)
+	if (mToolbars[TOOLBAR_BOTTOM])
 	{
-		toolbar_set.bottom_toolbar.button_display_mode = mToolbarBottom->getButtonType();
-		addToToolset(mToolbarBottom->getCommandsList(),toolbar_set.bottom_toolbar);
+		toolbar_set.bottom_toolbar.button_display_mode = mToolbars[TOOLBAR_BOTTOM]->getButtonType();
+		addToToolset(mToolbars[TOOLBAR_BOTTOM]->getCommandsList(), toolbar_set.bottom_toolbar);
 	}
 	
 	// Serialize the parameter tree
@@ -361,33 +407,36 @@ void LLToolBarView::onToolBarButtonAdded(LLView* button)
 
 void LLToolBarView::draw()
 {
-	//LLPanel* sizer_left = getChild<LLPanel>("sizer_left");
+	LLRect toolbar_rects[TOOLBAR_COUNT];
 	
-	LLRect bottom_rect, left_rect, right_rect;
-
-	if (mToolbarBottom) 
-	{
-		mToolbarBottom->getParent()->reshape(mToolbarBottom->getParent()->getRect().getWidth(), mToolbarBottom->getRect().getHeight());
-		mToolbarBottom->localRectToOtherView(mToolbarBottom->getLocalRect(), &bottom_rect, this);
-	}
-	if (mToolbarLeft)   
+	for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
 	{
-		mToolbarLeft->getParent()->reshape(mToolbarLeft->getRect().getWidth(), mToolbarLeft->getParent()->getRect().getHeight());
-		mToolbarLeft->localRectToOtherView(mToolbarLeft->getLocalRect(), &left_rect, this);
-	}
-	if (mToolbarRight)  
-	{
-		mToolbarRight->getParent()->reshape(mToolbarRight->getRect().getWidth(), mToolbarRight->getParent()->getRect().getHeight());
-		mToolbarRight->localRectToOtherView(mToolbarRight->getLocalRect(), &right_rect, this);
+		if (mToolbars[i])
+		{
+			LLLayoutStack::ELayoutOrientation orientation = LLToolBarEnums::getOrientation(mToolbars[i]->getSideType());
+
+			if (orientation == LLLayoutStack::HORIZONTAL)
+			{
+				mToolbars[i]->getParent()->reshape(mToolbars[i]->getParent()->getRect().getWidth(), mToolbars[i]->getRect().getHeight());
+			}
+			else
+			{
+				mToolbars[i]->getParent()->reshape(mToolbars[i]->getRect().getWidth(), mToolbars[i]->getParent()->getRect().getHeight());
+			}
+
+			mToolbars[i]->localRectToOtherView(mToolbars[i]->getLocalRect(), &toolbar_rects[i], this);
+		}
 	}
 	
 	// Draw drop zones if drop of a tool is active
 	if (isToolDragged())
 	{
 		LLColor4 drop_color = LLUIColorTable::instance().getColor( "ToolbarDropZoneColor" );
-		gl_rect_2d(bottom_rect, drop_color, TRUE);
-		gl_rect_2d(left_rect, drop_color, TRUE);
-		gl_rect_2d(right_rect, drop_color, TRUE);
+
+		for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+		{
+			gl_rect_2d(toolbar_rects[i], drop_color, TRUE);
+		}
 	}
 	
 	LLUICtrl::draw();
@@ -399,9 +448,9 @@ void LLToolBarView::draw()
 // ----------------------------------------
 
 
-void LLToolBarView::startDragTool(S32 x, S32 y, LLToolBarButton* button)
+void LLToolBarView::startDragTool(S32 x, S32 y, LLToolBarButton* toolbarButton)
 {
-	resetDragTool(button);
+	resetDragTool(toolbarButton);
 
 	// Flag the tool dragging but don't start it yet
 	LLToolDragAndDrop::getInstance()->setDragStart( x, y );
@@ -427,9 +476,7 @@ BOOL LLToolBarView::handleDragTool( S32 x, S32 y, const LLUUID& uuid, LLAssetTyp
 
 			// Second, stop the command if it is in progress and requires stopping!
 			LLCommandId command_id = LLCommandId(uuid);
-			gToolBarView->mToolbarLeft->stopCommandInProgress(command_id);
-			gToolBarView->mToolbarRight->stopCommandInProgress(command_id);
-			gToolBarView->mToolbarBottom->stopCommandInProgress(command_id);
+			gToolBarView->stopCommandInProgress(command_id);
 
 			gToolBarView->mDragStarted = true;
 			return TRUE;
@@ -460,10 +507,10 @@ BOOL LLToolBarView::handleDropTool( void* cargo_data, S32 x, S32 y, LLToolBar* t
 		{
 			// Suppress the command from the toolbars (including the one it's dropped in, 
 			// this will handle move position).
-			bool command_present = gToolBarView->hasCommand(command_id);
+			S32 old_toolbar_loc = gToolBarView->hasCommand(command_id);
 			LLToolBar* old_toolbar = NULL;
 
-			if (command_present)
+			if (old_toolbar_loc != TOOLBAR_NONE)
 			{
 				llassert(gToolBarView->mDragToolbarButton);
 				old_toolbar = gToolBarView->mDragToolbarButton->getParentByType<LLToolBar>();
@@ -473,9 +520,8 @@ BOOL LLToolBarView::handleDropTool( void* cargo_data, S32 x, S32 y, LLToolBar* t
 				}
 				else
 				{
-					gToolBarView->mToolbarBottom->removeCommand(command_id);
-					gToolBarView->mToolbarLeft->removeCommand(command_id);
-					gToolBarView->mToolbarRight->removeCommand(command_id);
+					int old_rank = LLToolBar::RANK_NONE;
+					gToolBarView->removeCommand(command_id, old_rank);
 				}
 			}
 
@@ -499,27 +545,29 @@ BOOL LLToolBarView::handleDropTool( void* cargo_data, S32 x, S32 y, LLToolBar* t
 	return handled;
 }
 
-void LLToolBarView::resetDragTool(LLToolBarButton* button)
+void LLToolBarView::resetDragTool(LLToolBarButton* toolbarButton)
 {
 	// Clear the saved command, toolbar and rank
 	gToolBarView->mDragStarted = false;
-	gToolBarView->mDragToolbarButton = button;
+	gToolBarView->mDragToolbarButton = toolbarButton;
 }
 
 void LLToolBarView::setToolBarsVisible(bool visible)
 {
-	mToolbarBottom->getParent()->setVisible(visible);
-	mToolbarLeft->getParent()->setVisible(visible);
-	mToolbarRight->getParent()->setVisible(visible);
+	for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+	{
+		mToolbars[i]->getParent()->setVisible(visible);
+	}
 }
 
 bool LLToolBarView::isModified() const
 {
 	bool modified = false;
 
-	modified |= mToolbarBottom->isModified();
-	modified |= mToolbarLeft->isModified();
-	modified |= mToolbarRight->isModified();
+	for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+	{
+		modified |= mToolbars[i]->isModified();
+	}
 
 	return modified;
 }
@@ -532,9 +580,11 @@ bool LLToolBarView::isModified() const
 void handleLoginToolbarSetup()
 {
 	// Open the destinations guide by default on first login, per Rhett
-	if (gSavedSettings.getBOOL("FirstLoginThisInstall") || gAgent.isFirstLogin())
+	if (gSavedPerAccountSettings.getBOOL("DisplayDestinationsOnInitialRun") || gAgent.isFirstLogin())
 	{
 		LLFloaterReg::showInstance("destinations");
+
+		gSavedPerAccountSettings.setBOOL("DisplayDestinationsOnInitialRun", FALSE);
 	}
 }
 
diff --git a/indra/newview/lltoolbarview.h b/indra/newview/lltoolbarview.h
index ea14e471cdf..3dc8954abec 100644
--- a/indra/newview/lltoolbarview.h
+++ b/indra/newview/lltoolbarview.h
@@ -39,6 +39,19 @@ class LLUICtrlFactory;
 class LLToolBarView : public LLUICtrl
 {
 public:
+	typedef enum
+	{
+		TOOLBAR_NONE = 0,
+		TOOLBAR_LEFT,
+		TOOLBAR_RIGHT,
+		TOOLBAR_BOTTOM,
+
+		TOOLBAR_COUNT,
+
+		TOOLBAR_FIRST = TOOLBAR_LEFT,
+		TOOLBAR_LAST = TOOLBAR_BOTTOM,
+	} EToolBarLocation;
+
 	// Xui structure of the toolbar panel
 	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> {};
 
@@ -52,6 +65,7 @@ class LLToolBarView : public LLUICtrl
 	{
 		Mandatory<LLToolBarEnums::ButtonType>	button_display_mode;
 		Multiple<LLCommandId::Params>	commands;
+
 		Toolbar();
 	};
 	struct ToolbarSet : public LLInitParam::Block<ToolbarSet>
@@ -59,6 +73,7 @@ class LLToolBarView : public LLUICtrl
 		Optional<Toolbar>	left_toolbar,
 							right_toolbar,
 							bottom_toolbar;
+
 		ToolbarSet();
 	};
 
@@ -66,9 +81,16 @@ class LLToolBarView : public LLUICtrl
 	virtual ~LLToolBarView();
 	virtual BOOL postBuild();
 	virtual void draw();
+
 	// Toolbar view interface with the rest of the world
-	// Checks if the commandId is being used somewhere in one of the toolbars
-	bool hasCommand(const LLCommandId& commandId) const;
+	// Checks if the commandId is being used somewhere in one of the toolbars, returns EToolBarLocation
+	S32 hasCommand(const LLCommandId& commandId) const;
+	S32 addCommand(const LLCommandId& commandId, EToolBarLocation toolbar, int rank = LLToolBar::RANK_NONE);
+	S32 removeCommand(const LLCommandId& commandId, int& rank);	// Sets the rank the removed command was at, RANK_NONE if not found
+	S32 enableCommand(const LLCommandId& commandId, bool enabled);
+	S32 stopCommandInProgress(const LLCommandId& commandId);
+	S32 flashCommand(const LLCommandId& commandId, bool flash);
+
 	// Loads the toolbars from the existing user or default settings
 	bool loadToolbars(bool force_default = false);	// return false if load fails
 	
@@ -76,10 +98,10 @@ class LLToolBarView : public LLUICtrl
 
 	static bool loadDefaultToolbars();
 	
-	static void startDragTool(S32 x, S32 y, LLToolBarButton* button);
+	static void startDragTool(S32 x, S32 y, LLToolBarButton* toolbarButton);
 	static BOOL handleDragTool(S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type);
 	static BOOL handleDropTool(void* cargo_data, S32 x, S32 y, LLToolBar* toolbar);
-	static void resetDragTool(LLToolBarButton* button);
+	static void resetDragTool(LLToolBarButton* toolbarButton);
 
 	bool isModified() const;
 	
@@ -91,15 +113,13 @@ class LLToolBarView : public LLUICtrl
 
 private:
 	void	saveToolbars() const;
-	bool	addCommand(const LLCommandId& commandId, LLToolBar*	toolbar);
+	bool	addCommandInternal(const LLCommandId& commandId, LLToolBar*	toolbar);
 	void	addToToolset(command_id_list_t& command_list, Toolbar& toolbar) const;
 
 	static void	onToolBarButtonAdded(LLView* button);
 
 	// Pointers to the toolbars handled by the toolbar view
-	LLToolBar*	mToolbarLeft;
-	LLToolBar*	mToolbarRight;
-	LLToolBar*	mToolbarBottom;
+	LLToolBar*  mToolbars[TOOLBAR_COUNT];
 	bool		mToolbarsLoaded;
 	
 	bool				mDragStarted;
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 308208869da..5e5bc0bde0a 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -3705,7 +3705,11 @@ Try enclosing path to the editor with double quotes.
   <string name="Command_View_Tooltip">Changing camera angle</string>
   <string name="Command_Voice_Tooltip">Volume controls for calls and people near you in world</string>
 
- <!-- Mesh UI terms -->
+  <string name="Toolbar_Bottom_Tooltip">currently in your bottom toolbar</string>
+  <string name="Toolbar_Left_Tooltip"  >currently in your left toolbar</string>
+  <string name="Toolbar_Right_Tooltip" >currently in your right toolbar</string>
+
+  <!-- Mesh UI terms -->
   <string name="Retain%">Retain%</string>
   <string name="Detail">Detail</string>
   <string name="Better Detail">Better Detail</string>
diff --git a/indra/newview/skins/default/xui/en/widgets/toolbar.xml b/indra/newview/skins/default/xui/en/widgets/toolbar.xml
index 7e7a9c61cfc..0aa478ace9f 100644
--- a/indra/newview/skins/default/xui/en/widgets/toolbar.xml
+++ b/indra/newview/skins/default/xui/en/widgets/toolbar.xml
@@ -30,6 +30,8 @@
                         image_overlay_alignment="left"
                         use_ellipses="true"
                         auto_resize="true"
+                        button_flash_count="99999"
+                        button_flash_rate="1.0"
                         flash_color="EmphasisColor"/>
   <button_icon pad_left="10"
                pad_right="10"
@@ -49,5 +51,7 @@
                chrome="true"
                use_ellipses="true"
                auto_resize="true"
+               button_flash_count="99999"
+               button_flash_rate="1.0"
                flash_color="EmphasisColor"/>
 </toolbar>
-- 
GitLab