diff --git a/doc/contributions.txt b/doc/contributions.txt
index 521be7b7e2318a47e4d42de625a34ae7f95655ee..a84ac7d53360d1a1e7c435f89354f15badff705f 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -751,6 +751,7 @@ Jonathan Yap
 	STORM-2088
 	STORM-2094
 	STORM-2099
+	STORM-2145
 Kadah Coba
 	STORM-1060
     STORM-1843
@@ -1460,6 +1461,7 @@ Whirly Fizzle
 	STORM-1930
 	BUG-6659
 	STORM-2078
+	BUG-17349
 Whoops Babii
 	VWR-631
 	VWR-1640
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 4f664a1ccc2a4c3cdd7d267b6682a552fca203e6..8b0e19e4f6edb06de5153da13dfabd1b50e1282b 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1839,7 +1839,7 @@ void LLFloater::onClickCloseBtn(bool app_quitting)
 // virtual
 void LLFloater::draw()
 {
-	const F32 alpha = getCurrentTransparency();
+	F32 alpha = getCurrentTransparency();
 
 	// draw background
 	if( isBackgroundVisible() )
@@ -1854,6 +1854,16 @@ void LLFloater::draw()
 		LLUIImage* image = NULL;
 		LLColor4 color;
 		LLColor4 overlay_color;
+		std::string help_topic;
+		if (this->findHelpTopic(help_topic))
+		{
+			if("camera_floater" == help_topic)
+			{
+				alpha = llmin(LLCachedControl<F32>(gSavedSettings, "CameraOpacity"),
+                              LLCachedControl<F32>(gSavedSettings, "ActiveFloaterTransparency"));
+			}
+		}
+
 		if (isBackgroundOpaque())
 		{
 			// NOTE: image may not be set
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index d6d7d2c563d77d515454db1a7e61135319466635..395aa785bfad06339faa5b6d46f98db7ae1a8171 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -460,6 +460,7 @@ set(viewer_SOURCE_FILES
     llpanelplaceprofile.cpp
     llpanelplaces.cpp
     llpanelplacestab.cpp
+    llpanelpresetscamerapulldown.cpp
     llpanelpresetspulldown.cpp
     llpanelprimmediacontrols.cpp
     llpanelprofile.cpp
@@ -1070,6 +1071,7 @@ set(viewer_HEADER_FILES
     llpanelplaceprofile.h
     llpanelplaces.h
     llpanelplacestab.h
+    llpanelpresetscamerapulldown.h
     llpanelpresetspulldown.h
     llpanelprimmediacontrols.h
     llpanelprofile.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 6621b9e269f6a2f0fcb937f4886de22e6dbe4570..541a5d070d20b6de6d693a0e2a1bc5a14502e02d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -15975,6 +15975,58 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+  <key>CameraOpacity</key>
+  <map>
+    <key>Comment</key>
+    <string>Opacity of the Camera Controls floater</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>1.0</real>
+  </map>
+  <key>PresetCameraActive</key>
+    <map>
+      <key>Comment</key>
+      <string>Name of currently selected preference</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string />
+    </map>
+    <key>CameraOffsetCustom0</key>
+    <map>
+      <key>Comment</key>
+      <string>Customized camera offset from avatar</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Vector3</string>
+      <key>Value</key>
+      <array>
+        <real>-3.0</real>
+        <real>0.0</real>
+        <real>0.75</real>
+      </array>
+    </map>
+    <key>FocusOffsetCustom0</key>
+    <map>
+      <key>Comment</key>
+      <string>Custom focus point offset relative to avatar (x-axis is forward)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Vector3D</string>
+      <key>Value</key>
+      <array>
+        <real>1.0</real>
+        <real>0.0</real>
+        <real>1.0</real>
+      </array>
+    </map>
 </map>
 </llsd>
 
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index e335eabd1af7bf29e8d2aa217228e6affc5f2386..1b006a23119412419a82999efda3089f1eb974a9 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -208,10 +208,12 @@ void LLAgentCamera::init()
 	mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView");
 	mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView");
 	mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView");
+	mCameraOffsetInitial[CAMERA_PRESET_CUSTOM0] = gSavedSettings.getControl("CameraOffsetCustom0");
 
 	mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView");
 	mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView");
 	mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView");
+	mFocusOffsetInitial[CAMERA_PRESET_CUSTOM0] = gSavedSettings.getControl("FocusOffsetCustom0");
 
 	mCameraCollidePlane.clearVec();
 	mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index ab793ff316b2ea54eef884323d6b81506b66a07b..29a1891d828abe86626e8c635db379a7bc53002a 100644
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -56,7 +56,10 @@ enum ECameraPreset
 	CAMERA_PRESET_FRONT_VIEW, 
 
 	/** "Above and to the left, over the shoulder, pulled back a little on the zoom" */
-	CAMERA_PRESET_GROUP_VIEW
+	CAMERA_PRESET_GROUP_VIEW,
+
+	/** Current view when a preset is saved */
+	CAMERA_PRESET_CUSTOM0
 };
 
 //------------------------------------------------------------------------
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index 20d650fa37187d3a97d98695e8402d2cef5a8bc8..777963bec5f331ff9801765e86b0d7749b6b2235 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -42,6 +42,7 @@
 #include "llslider.h"
 #include "llfirstuse.h"
 #include "llhints.h"
+#include "lltabcontainer.h"
 
 static LLDefaultChildRegistry::Register<LLPanelCameraItem> r("panel_camera_item");
 
@@ -353,6 +354,7 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val)
 {
 	LLHints::registerHintTarget("view_popup", getHandle());
 	mCommitCallbackRegistrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
+	mCommitCallbackRegistrar.add("Presets.GoViewPrefs", boost::bind(&LLFloaterCamera::onViewButtonClick, this, _2));
 }
 
 // virtual
@@ -376,6 +378,24 @@ BOOL LLFloaterCamera::postBuild()
 	return LLFloater::postBuild();
 }
 
+void LLFloaterCamera::onViewButtonClick(const LLSD& user_data)
+{
+	// bring up the prefs floater
+	LLFloater* prefsfloater = LLFloaterReg::showInstance("preferences");
+	if (prefsfloater)
+	{
+		// grab the 'view' panel from the preferences floater and
+		// bring it the front!
+		LLTabContainer* tabcontainer = prefsfloater->getChild<LLTabContainer>("pref core");
+		LLPanel* graphicspanel = prefsfloater->getChild<LLPanel>("move");
+		if (tabcontainer && graphicspanel)
+		{
+			tabcontainer->selectTabPanel(graphicspanel);
+		}
+	}
+}
+
+
 void LLFloaterCamera::fillFlatlistFromPanel (LLFlatListView* list, LLPanel* panel)
 {
 	// copying child list and then iterating over a copy, because list itself
diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h
index 4d6d03f22d9078e150720bf44b6ee3fdba7753c1..3601813bc10429a0f53f92173c1322c41c6cca8d 100644
--- a/indra/newview/llfloatercamera.h
+++ b/indra/newview/llfloatercamera.h
@@ -91,6 +91,8 @@ class LLFloaterCamera : public LLFloater
 
 	/*virtual*/ BOOL postBuild();
 
+	void onViewButtonClick(const LLSD& user_data);
+
 	ECameraControlMode determineMode();
 
 	/* resets to the previous mode */
diff --git a/indra/newview/llfloaterdeleteprefpreset.cpp b/indra/newview/llfloaterdeleteprefpreset.cpp
index 7dedbbf98430169016ec275228f84c7bcdfae203..bd62849b422749176eec52c643ac6256b4b2b50b 100644
--- a/indra/newview/llfloaterdeleteprefpreset.cpp
+++ b/indra/newview/llfloaterdeleteprefpreset.cpp
@@ -60,13 +60,15 @@ void LLFloaterDeletePrefPreset::onOpen(const LLSD& key)
 {
 	mSubdirectory = key.asString();
 	std::string floater_title = getString(std::string("title_") + mSubdirectory);
-
 	setTitle(floater_title);
 
 	LLComboBox* combo = getChild<LLComboBox>("preset_combo");
-
 	EDefaultOptions option = DEFAULT_HIDE;
-	LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option);
+	bool action;
+	action = LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option);
+
+	LLButton* delete_btn = getChild<LLButton>("delete");
+	delete_btn->setEnabled(action);
 }
 
 void LLFloaterDeletePrefPreset::onBtnDelete()
@@ -87,12 +89,10 @@ void LLFloaterDeletePrefPreset::onBtnDelete()
 void LLFloaterDeletePrefPreset::onPresetsListChange()
 {
 	LLComboBox* combo = getChild<LLComboBox>("preset_combo");
-	LLButton* delete_btn = getChild<LLButton>("delete");
 
 	EDefaultOptions option = DEFAULT_HIDE;
-	LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option);
 
-	delete_btn->setEnabled(0 != combo->getItemCount());
+	LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, combo, option);
 }
 
 void LLFloaterDeletePrefPreset::onBtnCancel()
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 100ee5ab72dd49cb3a64a5fb01dcd12276794586..6e5a773c33624707987e6a31fcaa84741a9cfee9 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -768,7 +768,8 @@ void LLFloaterPreference::onOpen(const LLSD& key)
 	saveSettings();
 
 	// Make sure there is a default preference file
-	LLPresetsManager::getInstance()->createMissingDefault();
+	LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA);
+	LLPresetsManager::getInstance()->createMissingDefault(PRESETS_GRAPHIC);
 
 	bool started = (LLStartUp::getStartupState() == STATE_STARTED);
 
@@ -776,9 +777,23 @@ void LLFloaterPreference::onOpen(const LLSD& key)
 	LLButton* save_btn = findChild<LLButton>("PrefSaveButton");
 	LLButton* delete_btn = findChild<LLButton>("PrefDeleteButton");
 
-	load_btn->setEnabled(started);
-	save_btn->setEnabled(started);
-	delete_btn->setEnabled(started);
+	if (load_btn && save_btn && delete_btn)
+	{
+		load_btn->setEnabled(started);
+		save_btn->setEnabled(started);
+		delete_btn->setEnabled(started);
+	}
+
+	LLButton* load_camera_btn = findChild<LLButton>("PrefCameraLoadButton");
+	LLButton* save_camera_btn = findChild<LLButton>("PrefCameraSaveButton");
+	LLButton* delete_camera_btn = findChild<LLButton>("PrefCameraDeleteButton");
+
+	if (load_camera_btn && save_camera_btn && delete_camera_btn)
+	{
+		load_camera_btn->setEnabled(started);
+		save_camera_btn->setEnabled(started);
+		delete_camera_btn->setEnabled(started);
+	}
 }
 
 void LLFloaterPreference::onVertexShaderEnable()
@@ -2128,6 +2143,11 @@ void LLFloaterPreference::changed()
 
 }
 
+void LLFloaterPreference::saveCameraPreset(std::string& preset)
+{
+	mSavedCameraPreset = preset;
+}
+
 void LLFloaterPreference::saveGraphicsPreset(std::string& preset)
 {
 	mSavedGraphicsPreset = preset;
@@ -2474,6 +2494,86 @@ class LLPanelPreferencePrivacy : public LLPanelPreference
 
 static LLPanelInjector<LLPanelPreferenceGraphics> t_pref_graph("panel_preference_graphics");
 static LLPanelInjector<LLPanelPreferencePrivacy> t_pref_privacy("panel_preference_privacy");
+static LLPanelInjector<LLPanelPreferenceView> t_pref_view("panel_preference_view");
+
+BOOL LLPanelPreferenceView::postBuild()
+{
+	setPresetText();
+
+	LLPresetsManager* presetsMgr = LLPresetsManager::getInstance();
+	if (presetsMgr)
+	{
+		presetsMgr->setPresetListChangeCameraCallback(boost::bind(&LLPanelPreferenceView::onPresetsListChangeCamera, this));
+		presetsMgr->createMissingDefault(PRESETS_CAMERA); // a no-op after the first time, but that's ok
+	}
+
+	return LLPanelPreference::postBuild();
+}
+
+void LLPanelPreferenceView::onPresetsListChangeCamera()
+{
+	LLPresetsManager* presetsMgr = LLPresetsManager::getInstance();
+	if (presetsMgr)
+	{
+		presetsMgr->setCameraDirty(false);
+	}
+
+	setPresetText();
+
+	LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+	if (instance && !gSavedSettings.getString("PresetCameraActive").empty())
+	{
+		instance->saveSettings(); //make cancel work correctly after changing the preset
+	}
+}
+
+void LLPanelPreferenceView::draw()
+{
+	setPresetText();
+	LLPanelPreference::draw();
+}
+
+void LLPanelPreferenceView::setPresetText()
+{
+	LLTextBox* preset_text = getChild<LLTextBox>("preset_camera_text");
+
+	std::string preset_camera_active = gSavedSettings.getString("PresetCameraActive");
+
+	if (!preset_camera_active.empty() && preset_camera_active != preset_text->getText())
+	{
+		LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+		if (instance)
+		{
+			instance->saveCameraPreset(preset_camera_active);
+		}
+	}
+
+	LLPresetsManager* presetsMgr = LLPresetsManager::getInstance();
+	if (presetsMgr)
+	{
+		if (presetsMgr->isCameraDirty() && !preset_camera_active.empty())
+		{
+			gSavedSettings.setString("PresetCameraActive", "");
+			preset_camera_active.clear();
+			// This doesn't seem to cause an infinite recursion.  This trigger is needed to cause the pulldown
+			// panel to update.
+			LLPresetsManager::getInstance()->triggerChangeCameraSignal();
+		}
+	}
+
+	if (!preset_camera_active.empty())
+	{
+		if (preset_camera_active == PRESETS_DEFAULT)
+		{
+			preset_camera_active = LLTrans::getString(PRESETS_DEFAULT);
+		}
+		preset_text->setText(preset_camera_active);
+	}
+	else
+	{
+		preset_text->setText(LLTrans::getString("none_paren_cap"));
+	}
+}
 
 BOOL LLPanelPreferenceGraphics::postBuild()
 {
@@ -2497,7 +2597,7 @@ BOOL LLPanelPreferenceGraphics::postBuild()
 
 	LLPresetsManager* presetsMgr = LLPresetsManager::getInstance();
     presetsMgr->setPresetListChangeCallback(boost::bind(&LLPanelPreferenceGraphics::onPresetsListChange, this));
-    presetsMgr->createMissingDefault(); // a no-op after the first time, but that's ok
+    presetsMgr->createMissingDefault(PRESETS_GRAPHIC); // a no-op after the first time, but that's ok
     
 	return LLPanelPreference::postBuild();
 }
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index fa0c09e97a7c901723c132d47bb3205b9ae52a8b..ea3a1fc98c56628e051f4d803ce6db381807c350 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -174,6 +174,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver,
 	void buildPopupLists();
 	static void refreshSkin(void* data);
 	void selectPanel(const LLSD& name);
+	void saveCameraPreset(std::string& preset);
 	void saveGraphicsPreset(std::string& preset);
 
 private:
@@ -196,6 +197,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver,
 	std::string mDirectoryVisibility;
 	
 	LLAvatarData mAvatarProperties;
+	std::string mSavedCameraPreset;
 	std::string mSavedGraphicsPreset;
 	LOG_CLASS(LLFloaterPreference);
 };
@@ -244,6 +246,18 @@ class LLPanelPreference : public LLPanel
 	LOG_CLASS(LLPanelPreference);
 };
 
+class LLPanelPreferenceView : public LLPanelPreference
+{
+public:
+	BOOL postBuild();
+	void draw();
+	void setPresetText();
+
+private:
+	void onPresetsListChangeCamera();
+	LOG_CLASS(LLPanelPreferenceView);
+};
+
 class LLPanelPreferenceGraphics : public LLPanelPreference
 {
 public:
@@ -261,7 +275,6 @@ class LLPanelPreferenceGraphics : public LLPanelPreference
 	bool hasDirtyChilds();
 
 private:
-
 	void onPresetsListChange();
 	LOG_CLASS(LLPanelPreferenceGraphics);
 };
diff --git a/indra/newview/llpanelpresetscamerapulldown.cpp b/indra/newview/llpanelpresetscamerapulldown.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2c95c06c310d2971283cb17eeffcfd338907e72a
--- /dev/null
+++ b/indra/newview/llpanelpresetscamerapulldown.cpp
@@ -0,0 +1,236 @@
+/** 
+ * @file llpanelpresetscamerapulldown.cpp
+ * @brief A panel showing a quick way to pick camera presets
+ *
+ * $LicenseInfo:firstyear=2017&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2017, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpanelpresetscamerapulldown.h"
+
+#include "llviewercontrol.h"
+#include "llstatusbar.h"
+
+#include "llbutton.h"
+#include "lltabcontainer.h"
+#include "llfloaterreg.h"
+#include "llfloaterpreference.h"
+#include "llpresetsmanager.h"
+#include "llsliderctrl.h"
+#include "llscrolllistctrl.h"
+#include "lltrans.h"
+
+/* static */ const F32 LLPanelPresetsCameraPulldown::sAutoCloseFadeStartTimeSec = 2.0f;
+/* static */ const F32 LLPanelPresetsCameraPulldown::sAutoCloseTotalTimeSec = 3.0f;
+
+///----------------------------------------------------------------------------
+/// Class LLPanelPresetsCameraPulldown
+///----------------------------------------------------------------------------
+
+// Default constructor
+LLPanelPresetsCameraPulldown::LLPanelPresetsCameraPulldown()
+{
+	mHoverTimer.stop();
+
+	mCommitCallbackRegistrar.add("Presets.GoViewPrefs", boost::bind(&LLPanelPresetsCameraPulldown::onViewButtonClick, this, _2));
+	mCommitCallbackRegistrar.add("PresetsCamera.RowClick", boost::bind(&LLPanelPresetsCameraPulldown::onRowClick, this, _2));
+
+	buildFromFile( "panel_presets_camera_pulldown.xml");
+}
+
+BOOL LLPanelPresetsCameraPulldown::postBuild()
+{
+	LLPresetsManager* presetsMgr = LLPresetsManager::getInstance();
+	if (presetsMgr)
+	{
+		presetsMgr->setPresetListChangeCameraCallback(boost::bind(&LLPanelPresetsCameraPulldown::populatePanel, this));
+LL_WARNS() << "DBG pulldown" << LL_ENDL;
+		// Make sure there is a default preference file
+		presetsMgr->createMissingDefault(PRESETS_CAMERA);
+		presetsMgr->startWatching(PRESETS_CAMERA);
+	}
+
+	populatePanel();
+
+	return LLPanel::postBuild();
+}
+
+void LLPanelPresetsCameraPulldown::populatePanel()
+{
+	std::string presets_dir = LLPresetsManager::getInstance()->getPresetsDir(PRESETS_CAMERA);
+	LLPresetsManager::getInstance()->loadPresetNamesFromDir(presets_dir, mPresetNames, DEFAULT_TOP);
+
+	LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("preset_camera_list");
+
+	if (scroll && mPresetNames.begin() != mPresetNames.end())
+	{
+		scroll->clearRows();
+
+		std::string active_preset = gSavedSettings.getString("PresetCameraActive");
+		if (active_preset == PRESETS_DEFAULT)
+		{
+			active_preset = LLTrans::getString(PRESETS_DEFAULT);
+		}
+
+		for (std::list<std::string>::const_iterator it = mPresetNames.begin(); it != mPresetNames.end(); ++it)
+		{
+			const std::string& name = *it;
+            LL_DEBUGS() << "adding '" << name << "'" << LL_ENDL;
+            
+			LLSD row;
+			row["columns"][0]["column"] = "preset_name";
+			row["columns"][0]["value"] = name;
+
+			bool is_selected_preset = false;
+			if (name == active_preset)
+			{
+				row["columns"][1]["column"] = "icon";
+				row["columns"][1]["type"] = "icon";
+				row["columns"][1]["value"] = "Check_Mark";
+
+				is_selected_preset = true;
+			}
+
+			LLScrollListItem* new_item = scroll->addElement(row);
+			new_item->setSelected(is_selected_preset);
+		}
+	}
+}
+
+/*virtual*/
+void LLPanelPresetsCameraPulldown::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+	mHoverTimer.stop();
+	LLPanel::onMouseEnter(x,y,mask);
+}
+
+/*virtual*/
+void LLPanelPresetsCameraPulldown::onTopLost()
+{
+	setVisible(FALSE);
+}
+
+/*virtual*/
+BOOL LLPanelPresetsCameraPulldown::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+    LLPanel::handleMouseDown(x,y,mask);
+    return TRUE;
+}
+
+/*virtual*/
+BOOL LLPanelPresetsCameraPulldown::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+    LLPanel::handleRightMouseDown(x, y, mask);
+    return TRUE;
+}
+
+/*virtual*/
+BOOL LLPanelPresetsCameraPulldown::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+    LLPanel::handleDoubleClick(x, y, mask);
+    return TRUE;
+}
+
+/*virtual*/
+void LLPanelPresetsCameraPulldown::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+	mHoverTimer.start();
+	LLPanel::onMouseLeave(x,y,mask);
+}
+
+/*virtual*/ 
+void LLPanelPresetsCameraPulldown::onVisibilityChange ( BOOL new_visibility )
+{
+	if (new_visibility)	
+	{
+		mHoverTimer.start(); // timer will be stopped when mouse hovers over panel
+	}
+	else
+	{
+		mHoverTimer.stop();
+
+	}
+}
+
+void LLPanelPresetsCameraPulldown::onRowClick(const LLSD& user_data)
+{
+	LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("preset_camera_list");
+
+	if (scroll)
+	{
+		LLScrollListItem* item = scroll->getFirstSelected();
+		if (item)
+		{
+			std::string name = item->getColumn(1)->getValue().asString();
+
+            LL_DEBUGS() << "selected '" << name << "'" << LL_ENDL;
+			LLPresetsManager::getInstance()->loadPreset(PRESETS_CAMERA, name);
+
+			setVisible(FALSE);
+		}
+        else
+        {
+            LL_DEBUGS() << "none selected" << LL_ENDL;
+        }
+	}
+    else
+    {
+        LL_DEBUGS() << "no scroll" << LL_ENDL;
+    }
+}
+
+void LLPanelPresetsCameraPulldown::onViewButtonClick(const LLSD& user_data)
+{
+	// close the minicontrol, we're bringing up the big one
+	setVisible(FALSE);
+
+	// bring up the prefs floater
+	LLFloater* prefsfloater = LLFloaterReg::showInstance("preferences");
+	if (prefsfloater)
+	{
+		// grab the 'view' panel from the preferences floater and
+		// bring it the front!
+		LLTabContainer* tabcontainer = prefsfloater->getChild<LLTabContainer>("pref core");
+		LLPanel* graphicspanel = prefsfloater->getChild<LLPanel>("move");
+		if (tabcontainer && graphicspanel)
+		{
+			tabcontainer->selectTabPanel(graphicspanel);
+		}
+	}
+}
+
+//virtual
+void LLPanelPresetsCameraPulldown::draw()
+{
+	F32 alpha = mHoverTimer.getStarted() 
+		? clamp_rescale(mHoverTimer.getElapsedTimeF32(), sAutoCloseFadeStartTimeSec, sAutoCloseTotalTimeSec, 1.f, 0.f)
+		: 1.0f;
+	LLViewDrawContext context(alpha);
+
+	LLPanel::draw();
+
+	if (alpha == 0.f)
+	{
+		setVisible(FALSE);
+	}
+}
diff --git a/indra/newview/llpanelpresetscamerapulldown.h b/indra/newview/llpanelpresetscamerapulldown.h
new file mode 100644
index 0000000000000000000000000000000000000000..12d9bc26ecfb3a2b35a5d5e291a9a68e6eb2644c
--- /dev/null
+++ b/indra/newview/llpanelpresetscamerapulldown.h
@@ -0,0 +1,62 @@
+/** 
+ * @file llpanelpresetscamerapulldown.h
+ * @brief A panel showing a quick way to pick camera presets
+ *
+ * $LicenseInfo:firstyear=2017&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2017, 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_LLPANELPRESETSCAMERAPULLDOWN_H
+#define LL_LLPANELPRESETSCAMERAPULLDOWN_H
+
+#include "linden_common.h"
+
+#include "llpanel.h"
+
+class LLFrameTimer;
+
+class LLPanelPresetsCameraPulldown : public LLPanel
+{
+ public:
+	LLPanelPresetsCameraPulldown();
+	/*virtual*/ void draw();
+	/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
+	/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
+    /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+    /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+    /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+	/*virtual*/ void onTopLost();
+	/*virtual*/ void onVisibilityChange ( BOOL new_visibility );
+	/*virtual*/ BOOL postBuild();
+	void populatePanel();
+	
+ private:
+	void onViewButtonClick(const LLSD& user_data);
+	void onRowClick(const LLSD& user_data);
+
+	std::list<std::string> mPresetNames;
+	LLFrameTimer mHoverTimer;
+	static const F32 sAutoCloseFadeStartTimeSec;
+	static const F32 sAutoCloseTotalTimeSec;
+    LOG_CLASS(LLPanelPresetsCameraPulldown);
+};
+
+#endif // LL_LLPANELPRESETSCAMERAPULLDOWN_H
diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp
index 9b4dc5474a08e644ed0121935862e91ebb848958..0bbf1781a5640f374b19cf78a825a7478ed36988 100644
--- a/indra/newview/llpanelpresetspulldown.cpp
+++ b/indra/newview/llpanelpresetspulldown.cpp
@@ -63,7 +63,7 @@ BOOL LLPanelPresetsPulldown::postBuild()
 	LLPresetsManager* presetsMgr = LLPresetsManager::getInstance();
     presetsMgr->setPresetListChangeCallback(boost::bind(&LLPanelPresetsPulldown::populatePanel, this));
 	// Make sure there is a default preference file
-    presetsMgr->createMissingDefault();
+    presetsMgr->createMissingDefault(PRESETS_GRAPHIC);
 
 	populatePanel();
 
diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp
index 836f63bffa696996cb8f262549cb3a729c91578e..16721a6efc064198c5f0e436a9ade74d28310976 100644
--- a/indra/newview/llpresetsmanager.cpp
+++ b/indra/newview/llpresetsmanager.cpp
@@ -39,6 +39,7 @@
 #include "llfloaterpreference.h"
 #include "llfloaterreg.h"
 #include "llfeaturemanager.h"
+#include "llagentcamera.h"
 
 LLPresetsManager::LLPresetsManager()
 {
@@ -46,6 +47,12 @@ LLPresetsManager::LLPresetsManager()
 
 LLPresetsManager::~LLPresetsManager()
 {
+	mCameraChangedSignal.disconnect();
+}
+
+void LLPresetsManager::triggerChangeCameraSignal()
+{
+	mPresetListChangeCameraSignal();
 }
 
 void LLPresetsManager::triggerChangeSignal()
@@ -53,15 +60,16 @@ void LLPresetsManager::triggerChangeSignal()
 	mPresetListChangeSignal();
 }
 
-void LLPresetsManager::createMissingDefault()
+void LLPresetsManager::createMissingDefault(const std::string& subdirectory)
 {
-	std::string default_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, PRESETS_GRAPHIC, PRESETS_DEFAULT + ".xml");
+	std::string default_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR,
+															  subdirectory, PRESETS_DEFAULT + ".xml");
 	if (!gDirUtilp->fileExists(default_file))
 	{
 		LL_INFOS() << "No default preset found -- creating one at " << default_file << LL_ENDL;
 
-		// Write current graphic settings as the default
-        savePreset(PRESETS_GRAPHIC, PRESETS_DEFAULT, true);
+		// Write current settings as the default
+        savePreset(subdirectory, PRESETS_DEFAULT, true);
 	}
     else
     {
@@ -69,6 +77,34 @@ void LLPresetsManager::createMissingDefault()
     }
 }
 
+void LLPresetsManager::startWatching(const std::string& subdirectory)
+{
+	if (PRESETS_CAMERA == subdirectory)
+	{
+		std::vector<std::string> name_list;
+		getControlNames(name_list);
+
+		for (std::vector<std::string>::iterator it = name_list.begin(); it != name_list.end(); ++it)
+		{
+			std::string ctrl_name = *it;
+LL_WARNS() << "DBG starting watch on " << ctrl_name << LL_ENDL;
+			if (gSavedSettings.controlExists(ctrl_name))
+			{
+				LLPointer<LLControlVariable> cntrl_ptr = gSavedSettings.getControl(ctrl_name);
+				if (cntrl_ptr.isNull())
+				{
+					LL_WARNS("Init") << "Unable to set signal on global setting '" << ctrl_name
+									<< "'" << LL_ENDL;
+				}
+				else
+				{
+					mCameraChangedSignal = cntrl_ptr->getCommitSignal()->connect(boost::bind(&settingChanged));
+				}
+			}
+		}
+	}
+}
+
 std::string LLPresetsManager::getPresetsDir(const std::string& subdirectory)
 {
 	std::string presets_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR);
@@ -134,6 +170,49 @@ void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_nam
 	presets = mPresetNames;
 }
 
+bool LLPresetsManager::mCameraDirty = false;
+
+void LLPresetsManager::setCameraDirty(bool dirty)
+{
+	mCameraDirty = dirty;
+}
+
+bool LLPresetsManager::isCameraDirty()
+{
+	return mCameraDirty;
+}
+
+void LLPresetsManager::settingChanged()
+{
+LL_WARNS() << "DBG setting changed" << LL_ENDL;
+	setCameraDirty(true);
+}
+
+void LLPresetsManager::getControlNames(std::vector<std::string>& names)
+{
+	names = boost::assign::list_of
+		("CameraOffsetCustom0")
+		("FocusOffsetCustom0")
+		// From panel_preferences_move.xml
+		("CameraAngle")
+		("CameraOffsetScale")
+		("CameraOpacity")
+		("EditCameraMovement")
+		("AppearanceCameraMovement")
+		// From llagentcamera.cpp
+		("RenderFarClip")
+		("CameraOffsetBuild")
+		("CameraPreset")
+		("CameraOffsetRearView")
+		("CameraOffsetFrontView")
+		("CameraOffsetGroupView")
+		("FocusOffsetRearView")
+		("FocusOffsetFrontView")
+		("FocusOffsetGroupView")
+		("CameraOffsetScale")
+		("TrackFocusObject");
+}
+
 bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string name, bool createDefault)
 {
 	if (LLTrans::getString(PRESETS_DEFAULT) == name)
@@ -149,94 +228,110 @@ bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string n
 		LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
 		if (instance && !createDefault)
 		{
-            gSavedSettings.setString("PresetGraphicActive", name);
+			gSavedSettings.setString("PresetGraphicActive", name);
 			instance->getControlNames(name_list);
-            LL_DEBUGS() << "saving preset '" << name << "'; " << name_list.size() << " names" << LL_ENDL;
+			LL_DEBUGS() << "saving preset '" << name << "'; " << name_list.size() << " names" << LL_ENDL;
 			name_list.push_back("PresetGraphicActive");
 		}
-        else
+		else
         {
-            LL_WARNS() << "preferences floater instance not found" << LL_ENDL;
-        }
+			LL_WARNS() << "preferences floater instance not found" << LL_ENDL;
+		}
 	}
-    else if(PRESETS_CAMERA == subdirectory)
+	else if(PRESETS_CAMERA == subdirectory)
 	{
-		name_list = boost::assign::list_of
-			("Placeholder");
+		gSavedSettings.setString("PresetGraphicActive", name);
+//		gSavedSettings.setU32("CameraPreset", CAMERA_PRESET_CUSTOM0);
+
+//		gSavedSettings.setVector3d("CameraOffsetCustom0", gAgentCamera.calcCameraPositionTargetGlobal());
+//		gSavedSettings.setVector3d("FocusOffsetCustom0", gAgentCamera.calcFocusPositionTargetGlobal());
+
+		getControlNames(name_list);
+		name_list.push_back("PresetCameraActive");
 	}
-    else
-    {
-        LL_ERRS() << "Invalid presets directory '" << subdirectory << "'" << LL_ENDL;
-    }
-    
-    if (name_list.size() > 1 // if the active preset name is the only thing in the list, don't save the list
-        || (createDefault && name == PRESETS_DEFAULT && subdirectory == PRESETS_GRAPHIC)) // or create a default graphics preset from hw recommended settings 
-    {
-        // make an empty llsd
-        LLSD paramsData(LLSD::emptyMap());
+	else
+	{
+		LL_ERRS() << "Invalid presets directory '" << subdirectory << "'" << LL_ENDL;
+	}
+ 
+	// make an empty llsd
+	LLSD paramsData(LLSD::emptyMap());
 
-        if (createDefault)
-        {
-            paramsData = LLFeatureManager::getInstance()->getRecommendedSettingsMap();
-            if (gSavedSettings.getU32("RenderAvatarMaxComplexity") == 0)
-            {
-                // use the recommended setting as an initial one (MAINT-6435)
-                gSavedSettings.setU32("RenderAvatarMaxComplexity", paramsData["RenderAvatarMaxComplexity"]["Value"].asInteger());
-            }
-        }
-        else
-        {
-            for (std::vector<std::string>::iterator it = name_list.begin(); it != name_list.end(); ++it)
-            {
-                std::string ctrl_name = *it;
-                LLControlVariable* ctrl = gSavedSettings.getControl(ctrl_name).get();
-                std::string comment = ctrl->getComment();
-                std::string type = LLControlGroup::typeEnumToString(ctrl->type());
-                LLSD value = ctrl->getValue();
-
-                paramsData[ctrl_name]["Comment"] = comment;
-                paramsData[ctrl_name]["Persist"] = 1;
-                paramsData[ctrl_name]["Type"] = type;
-                paramsData[ctrl_name]["Value"] = value;
-            }
-        }
-
-        std::string pathName(getPresetsDir(subdirectory) + gDirUtilp->getDirDelimiter() + LLURI::escape(name) + ".xml");
-
-        // write to file
-        llofstream presetsXML(pathName.c_str());
-        if (presetsXML.is_open())
-        {
-            
-            LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
-            formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY);
-            presetsXML.close();
-            saved = true;
+	// Create a default graphics preset from hw recommended settings 
+	if (createDefault && name == PRESETS_DEFAULT && subdirectory == PRESETS_GRAPHIC)
+	{
+		paramsData = LLFeatureManager::getInstance()->getRecommendedSettingsMap();
+		if (gSavedSettings.getU32("RenderAvatarMaxComplexity") == 0)
+		{
+			// use the recommended setting as an initial one (MAINT-6435)
+			gSavedSettings.setU32("RenderAvatarMaxComplexity", paramsData["RenderAvatarMaxComplexity"]["Value"].asInteger());
+		}
+	}
+	else
+	{
+		for (std::vector<std::string>::iterator it = name_list.begin(); it != name_list.end(); ++it)
+		{
+			std::string ctrl_name = *it;
+			LLControlVariable* ctrl = gSavedSettings.getControl(ctrl_name).get();
+			std::string comment = ctrl->getComment();
+			std::string type = LLControlGroup::typeEnumToString(ctrl->type());
+			LLSD value = ctrl->getValue();
+
+			paramsData[ctrl_name]["Comment"] = comment;
+			paramsData[ctrl_name]["Persist"] = 1;
+			paramsData[ctrl_name]["Type"] = type;
+			paramsData[ctrl_name]["Value"] = value;
+		}
+	}
+
+	std::string pathName(getPresetsDir(subdirectory) + gDirUtilp->getDirDelimiter() + LLURI::escape(name) + ".xml");
+
+ // If the active preset name is the only thing in the list, don't save the list
+	if (paramsData.size() > 1)
+	{
+		// write to file
+		llofstream presetsXML(pathName.c_str());
+		if (presetsXML.is_open())
+		{
+			LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+			formatter->format(paramsData, presetsXML, LLSDFormatter::OPTIONS_PRETTY);
+			presetsXML.close();
+			saved = true;
             
-            LL_DEBUGS() << "saved preset '" << name << "'; " << paramsData.size() << " parameters" << LL_ENDL;
-
-            if (!createDefault)
-            {
-                gSavedSettings.setString("PresetGraphicActive", name);
-                // signal interested parties
-                triggerChangeSignal();
-            }
-        }
-        else
-        {
-            LL_WARNS("Presets") << "Cannot open for output preset file " << pathName << LL_ENDL;
-        }
-    }
+			LL_DEBUGS() << "saved preset '" << name << "'; " << paramsData.size() << " parameters" << LL_ENDL;
+
+			if (subdirectory == PRESETS_GRAPHIC)
+			{
+				gSavedSettings.setString("PresetGraphicActive", name);
+				// signal interested parties
+				triggerChangeSignal();
+			}
+
+			if (subdirectory == PRESETS_CAMERA)
+			{
+				gSavedSettings.setString("PresetCameraActive", name);
+				setCameraDirty(false);
+				// signal interested parties
+				triggerChangeCameraSignal();
+			}
+		}
+		else
+		{
+			LL_WARNS("Presets") << "Cannot open for output preset file " << pathName << LL_ENDL;
+		}
+	}
     else
-    {
-        LL_INFOS() << "No settings found; preferences floater has not yet been created" << LL_ENDL;
-    }
+	{
+		LL_INFOS() << "No settings available to be saved" << LL_ENDL;
+	}
     
 	return saved;
 }
 
-void LLPresetsManager::setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option)
+bool LLPresetsManager::setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option)
 {
+	bool sts = true;
+
 	combo->clearRows();
 
 	std::string presets_dir = getPresetsDir(subdirectory);
@@ -259,8 +354,10 @@ void LLPresetsManager::setPresetNamesInComboBox(const std::string& subdirectory,
 		else
 		{
 			combo->setLabel(LLTrans::getString("preset_combo_label"));
+			sts = false;
 		}
 	}
+	return sts;
 }
 
 void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string name)
@@ -279,14 +376,19 @@ void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string n
 		if(PRESETS_GRAPHIC == subdirectory)
 		{
 			gSavedSettings.setString("PresetGraphicActive", name);
-		}
 
-		LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
-		if (instance)
+			LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+			if (instance)
+			{
+				instance->refreshEnabledGraphics();
+			}
+			triggerChangeSignal();
+		}
+		if(PRESETS_CAMERA == subdirectory)
 		{
-			instance->refreshEnabledGraphics();
+			gSavedSettings.setString("PresetCameraActive", name);
+			triggerChangeCameraSignal();
 		}
-		triggerChangeSignal();
 	}
     else
     {
@@ -317,17 +419,34 @@ bool LLPresetsManager::deletePreset(const std::string& subdirectory, std::string
 	}
 
 	// If you delete the preset that is currently marked as loaded then also indicate that no preset is loaded.
-	if (gSavedSettings.getString("PresetGraphicActive") == name)
+	if(PRESETS_GRAPHIC == subdirectory)
 	{
-		gSavedSettings.setString("PresetGraphicActive", "");
+		if (gSavedSettings.getString("PresetGraphicActive") == name)
+		{
+			gSavedSettings.setString("PresetGraphicActive", "");
+		}
+		// signal interested parties
+		triggerChangeSignal();
 	}
 
-	// signal interested parties
-	triggerChangeSignal();
+	if(PRESETS_CAMERA == subdirectory)
+	{
+		if (gSavedSettings.getString("PresetCameraActive") == name)
+		{
+			gSavedSettings.setString("PresetCameraActive", "");
+		}
+		// signal interested parties
+		triggerChangeCameraSignal();
+	}
 
 	return sts;
 }
 
+boost::signals2::connection LLPresetsManager::setPresetListChangeCameraCallback(const preset_list_signal_t::slot_type& cb)
+{
+	return mPresetListChangeCameraSignal.connect(cb);
+}
+
 boost::signals2::connection LLPresetsManager::setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb)
 {
 	return mPresetListChangeSignal.connect(cb);
diff --git a/indra/newview/llpresetsmanager.h b/indra/newview/llpresetsmanager.h
index 21f9885f2786c9d4ec95c0db2462a62488982e50..71ec4736b23c348f343972a6853ee3d885b0f4e9 100644
--- a/indra/newview/llpresetsmanager.h
+++ b/indra/newview/llpresetsmanager.h
@@ -51,16 +51,21 @@ class LLPresetsManager : public LLSingleton<LLPresetsManager>
 	typedef std::list<std::string> preset_name_list_t;
 	typedef boost::signals2::signal<void()> preset_list_signal_t;
 
-	void createMissingDefault();
+	void createMissingDefault(const std::string& subdirectory);
+	void startWatching(const std::string& subdirectory);
+	void triggerChangeCameraSignal();
 	void triggerChangeSignal();
 	static std::string getPresetsDir(const std::string& subdirectory);
-	void setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option);
+	bool setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option);
 	void loadPresetNamesFromDir(const std::string& dir, preset_name_list_t& presets, EDefaultOptions default_option);
 	bool savePreset(const std::string& subdirectory, std::string name, bool createDefault = false);
 	void loadPreset(const std::string& subdirectory, std::string name);
 	bool deletePreset(const std::string& subdirectory, std::string name);
+	bool isCameraDirty();
+	static void setCameraDirty(bool dirty);
 
 	// Emitted when a preset gets loaded, deleted, or saved.
+	boost::signals2::connection setPresetListChangeCameraCallback(const preset_list_signal_t::slot_type& cb);
 	boost::signals2::connection setPresetListChangeCallback(const preset_list_signal_t::slot_type& cb);
 
 	// Emitted when a preset gets loaded or saved.
@@ -70,10 +75,18 @@ class LLPresetsManager : public LLSingleton<LLPresetsManager>
 	LLPresetsManager();
 	~LLPresetsManager();
 
+	preset_list_signal_t mPresetListChangeCameraSignal;
 	preset_list_signal_t mPresetListChangeSignal;
 
   private:
-    LOG_CLASS(LLPresetsManager);
+	LOG_CLASS(LLPresetsManager);
+
+	void getControlNames(std::vector<std::string>& names);
+	static void LLPresetsManager::settingChanged();
+
+	boost::signals2::connection	mCameraChangedSignal;
+
+	static bool	mCameraDirty;
 };
 
 #endif // LL_PRESETSMANAGER_H
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 041eae4b3c9cd36af417dd1fe2a02581f667c9a2..702b9a84846fa6e6b6835901ff28aa57e8f07997 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -38,6 +38,7 @@
 #include "llfloaterbuycurrency.h"
 #include "llbuycurrencyhtml.h"
 #include "llpanelnearbymedia.h"
+#include "llpanelpresetscamerapulldown.h"
 #include "llpanelpresetspulldown.h"
 #include "llpanelvolumepulldown.h"
 #include "llfloaterregioninfo.h"
@@ -171,8 +172,11 @@ BOOL LLStatusBar::postBuild()
 	
 	mBtnStats = getChildView("stat_btn");
 
-	mIconPresets = getChild<LLIconCtrl>( "presets_icon" );
-	mIconPresets->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterPresets, this));
+	mIconPresetsCamera = getChild<LLIconCtrl>( "presets_icon_camera" );
+	mIconPresetsCamera->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterPresetsCamera, this));
+
+	mIconPresetsGraphic = getChild<LLIconCtrl>( "presets_icon_graphic" );
+	mIconPresetsGraphic->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterPresets, this));
 
 	mBtnVolume = getChild<LLButton>( "volume_btn" );
 	mBtnVolume->setClickedCallback( onClickVolume, this );
@@ -227,6 +231,11 @@ BOOL LLStatusBar::postBuild()
 	mSGPacketLoss = LLUICtrlFactory::create<LLStatGraph>(pgp);
 	addChild(mSGPacketLoss);
 
+	mPanelPresetsCameraPulldown = new LLPanelPresetsCameraPulldown();
+	addChild(mPanelPresetsCameraPulldown);
+	mPanelPresetsCameraPulldown->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
+	mPanelPresetsCameraPulldown->setVisible(FALSE);
+
 	mPanelPresetsPulldown = new LLPanelPresetsPulldown();
 	addChild(mPanelPresetsPulldown);
 	mPanelPresetsPulldown->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
@@ -325,7 +334,8 @@ void LLStatusBar::setVisibleForMouselook(bool visible)
 	mSGBandwidth->setVisible(visible);
 	mSGPacketLoss->setVisible(visible);
 	setBackgroundVisible(visible);
-	mIconPresets->setVisible(visible);
+	mIconPresetsCamera->setVisible(visible);
+	mIconPresetsGraphic->setVisible(visible);
 }
 
 void LLStatusBar::debitBalance(S32 debit)
@@ -470,10 +480,34 @@ void LLStatusBar::onClickBuyCurrency()
 	LLFirstUse::receiveLindens(false);
 }
 
+void LLStatusBar::onMouseEnterPresetsCamera()
+{
+	LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder");
+	LLIconCtrl* icon =  getChild<LLIconCtrl>( "presets_icon_camera" );
+	LLRect icon_rect = icon->getRect();
+	LLRect pulldown_rect = mPanelPresetsCameraPulldown->getRect();
+	pulldown_rect.setLeftTopAndSize(icon_rect.mLeft -
+	     (pulldown_rect.getWidth() - icon_rect.getWidth()),
+			       icon_rect.mBottom,
+			       pulldown_rect.getWidth(),
+			       pulldown_rect.getHeight());
+
+	pulldown_rect.translate(popup_holder->getRect().getWidth() - pulldown_rect.mRight, 0);
+	mPanelPresetsCameraPulldown->setShape(pulldown_rect);
+
+	// show the master presets pull-down
+	LLUI::clearPopups();
+	LLUI::addPopup(mPanelPresetsCameraPulldown);
+	mPanelNearByMedia->setVisible(FALSE);
+	mPanelVolumePulldown->setVisible(FALSE);
+	mPanelPresetsPulldown->setVisible(FALSE);
+	mPanelPresetsCameraPulldown->setVisible(TRUE);
+}
+
 void LLStatusBar::onMouseEnterPresets()
 {
 	LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder");
-	LLIconCtrl* icon =  getChild<LLIconCtrl>( "presets_icon" );
+	LLIconCtrl* icon =  getChild<LLIconCtrl>( "presets_icon_graphic" );
 	LLRect icon_rect = icon->getRect();
 	LLRect pulldown_rect = mPanelPresetsPulldown->getRect();
 	pulldown_rect.setLeftTopAndSize(icon_rect.mLeft -
@@ -512,6 +546,7 @@ void LLStatusBar::onMouseEnterVolume()
 	// show the master volume pull-down
 	LLUI::clearPopups();
 	LLUI::addPopup(mPanelVolumePulldown);
+	mPanelPresetsCameraPulldown->setVisible(FALSE);
 	mPanelPresetsPulldown->setVisible(FALSE);
 	mPanelNearByMedia->setVisible(FALSE);
 	mPanelVolumePulldown->setVisible(TRUE);
@@ -536,6 +571,7 @@ void LLStatusBar::onMouseEnterNearbyMedia()
 	LLUI::clearPopups();
 	LLUI::addPopup(mPanelNearByMedia);
 
+	mPanelPresetsCameraPulldown->setVisible(FALSE);
 	mPanelPresetsPulldown->setVisible(FALSE);
 	mPanelVolumePulldown->setVisible(FALSE);
 	mPanelNearByMedia->setVisible(TRUE);
diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h
index 277f039f204cde31066f9aee967d26255d6d8c71..507afcd147d73c21f275c8895eb1301e3b18c898 100644
--- a/indra/newview/llstatusbar.h
+++ b/indra/newview/llstatusbar.h
@@ -41,6 +41,7 @@ class LLUICtrl;
 class LLUUID;
 class LLFrameTimer;
 class LLStatGraph;
+class LLPanelPresetsCameraPulldown;
 class LLPanelPresetsPulldown;
 class LLPanelVolumePulldown;
 class LLPanelNearByMedia;
@@ -91,6 +92,7 @@ class LLStatusBar
 	void onClickBuyCurrency();
 	void onVolumeChanged(const LLSD& newvalue);
 
+	void onMouseEnterPresetsCamera();
 	void onMouseEnterPresets();
 	void onMouseEnterVolume();
 	void onMouseEnterNearbyMedia();
@@ -106,7 +108,8 @@ class LLStatusBar
 	LLStatGraph *mSGPacketLoss;
 
 	LLView		*mBtnStats;
-	LLIconCtrl	*mIconPresets;
+	LLIconCtrl	*mIconPresetsCamera;
+	LLIconCtrl	*mIconPresetsGraphic;
 	LLButton	*mBtnVolume;
 	LLTextBox	*mBoxBalance;
 	LLButton	*mMediaToggle;
@@ -119,6 +122,7 @@ class LLStatusBar
 	S32				mSquareMetersCommitted;
 	LLFrameTimer*	mBalanceTimer;
 	LLFrameTimer*	mHealthTimer;
+	LLPanelPresetsCameraPulldown* mPanelPresetsCameraPulldown;
 	LLPanelPresetsPulldown* mPanelPresetsPulldown;
 	LLPanelVolumePulldown* mPanelVolumePulldown;
 	LLPanelNearByMedia*	mPanelNearByMedia;
diff --git a/indra/newview/skins/default/textures/icons/Presets_Icon_Camera.png b/indra/newview/skins/default/textures/icons/Presets_Icon_Camera.png
new file mode 100644
index 0000000000000000000000000000000000000000..8cb51cdc8e25e48f4d12e7cfd569e3f0daa5d04a
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Presets_Icon_Camera.png differ
diff --git a/indra/newview/skins/default/textures/icons/Presets_Icon.png b/indra/newview/skins/default/textures/icons/Presets_Icon_Graphic.png
similarity index 100%
rename from indra/newview/skins/default/textures/icons/Presets_Icon.png
rename to indra/newview/skins/default/textures/icons/Presets_Icon_Graphic.png
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index f2da22256c4914d9d91ea83df73e56302d87ee3e..de9ed4d47974a8d2fb43a121719b87bbb53e1a51 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -205,7 +205,8 @@ with the same filename but different name
 
   <texture name="Facebook_Icon" file_name="icons/Facebook.png" preload="false" />
 
-  <texture name="Presets_Icon" file_name="icons/Presets_Icon.png" preload="true" />
+  <texture name="Presets_Icon_Graphic" file_name="icons/Presets_Icon_Graphic.png" preload="true" />
+  <texture name="Presets_Icon_Camera" file_name="icons/Presets_Icon_Camera.png" preload="true" />
 
   <texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.png" preload="false" />
   <texture name="Favorite_Star_Off" file_name="navbar/Favorite_Star_Off.png" preload="false" />
diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml
index 521389d7b3a18582eb9e43da4340127263af4b0f..4eec922915dcc2c77173e77ad7a68f084c0f0a5f 100644
--- a/indra/newview/skins/default/xui/en/floater_camera.xml
+++ b/indra/newview/skins/default/xui/en/floater_camera.xml
@@ -150,8 +150,26 @@
             left="0"
             mouse_opaque="false"
             name="zoom"
-            top="20"
+            top="0"
             width="226">
+         <slider
+            can_edit_text="true"
+            control_name="CameraAngle"
+            decimal_digits="2"
+            follows="left|top"
+            height="16"
+            top="20"
+            increment="0.025"
+            initial_value="1.57"
+            layout="topleft"
+            label_width="112"
+            label="View angle"
+            left="10"
+            max_val="1.6"
+            min_val="0.17"
+            name="camera_fov"
+            show_text="false"
+            width="200" />
            <joystick_rotate
               follows="top|left"
               height="78"
@@ -162,7 +180,7 @@
               sound_flags="3"
               visible="true"
               tool_tip="Orbit camera around focus"
-              top="20"
+              top_delta="20"
               width="78" />                      
            <button
               follows="top|left"
@@ -174,7 +192,7 @@
               left_pad="14" 
               name="zoom_plus_btn"
               width="18"
-              top="18">
+              top="38">
              <commit_callback
                 function="Zoom.plus" />
              <mouse_held_callback
@@ -219,7 +237,7 @@
          scale_image="false"
          sound_flags="3"
          tool_tip="Move camera up and down, left and right"
-         top="20"
+         top="40"
          width="78"/>
         </panel>
     </panel>
@@ -270,5 +288,17 @@
          tool_tip="Camera modes"
          width="25">
         </button>
+
+	<button
+		name="open_prefs_btn"
+		image_overlay="Icon_Gear_Foreground"
+		tool_tip = "Open view preferences"
+		left_pad="45"
+		height="22"
+		width="28">
+	  <button.commit_callback
+		  function="Presets.GoViewPrefs" />
+	</button>
+
     </panel>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index 9a9101e0da1f71e9f54012634d8a457562c4fe25..cbaeae5b94e563b7f8f78cd73de14163a86195a0 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -79,7 +79,7 @@
          help_topic="preferences_chat_tab"
          name="chat" />
         <panel
-		 class="panel_preference"
+		 class="panel_preference_view"
          filename="panel_preferences_move.xml"
          label="Move &amp; View"
          layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index 32cbbff8b772cb5280241dff48ce6be9888c3a2c..f0979915ce31cec266fdb3294ba01af1e1d96947 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -266,6 +266,21 @@
        0
   </text>
 
+<text
+type="string"
+length="1"
+follows="left|top"
+height="16"
+layout="topleft"
+left_delta="68"
+name="IndirectMaxComplexityLink"
+mouse_opaque="false"
+top_delta="0"
+width="120">
+[https://community.secondlife.com/t5/Featured-News/Why-are-all-these-people-made-of-colored-jelly/ba-p/3031255 What's this?]
+</text>
+
+
   <check_box
     control_name="WindLightUseAtmosShaders"
     height="16"
@@ -323,7 +338,6 @@
       function="Pref.PrefLoad"
 	  parameter="graphic"/>
   </button>
-         min_val="0.125"
 
   <button
     follows="top|left"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
index 8794e3bf95ac9d54e4084203b16433e6b5a72208..e4a5f5e283e508a6b7b7f143810c9aac0417e170 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
@@ -2,13 +2,14 @@
 <panel
  border="true"
  follows="left|top|right|bottom"
- height="408"
+ height="418"
  label="Move"
  layout="topleft"
  left="102"
  name="move_panel"
  top="1"
  width="517">
+
   <icon
      follows="left|top"
      height="18"
@@ -19,19 +20,41 @@
      visible="true"
      width="18"
      left="30"
-     top="10"/>
+     top="4"/>
+
+  <text
+    follows="top|left|right"
+    height="16"
+    layout="topleft"
+    left="80"
+    top_delta="0"
+    width="100">
+      Preset in use:
+  </text>
+
+  <text
+    follows="top|left|right"
+    height="16"
+    layout="topleft"
+    left_delta="100"
+    name="preset_camera_text"
+    width="120">
+      (None)
+  </text>
+
   <slider
    can_edit_text="true"
    control_name="CameraAngle"
    decimal_digits="2"
    follows="left|top"
    height="16"
+   top_pad="5"
    increment="0.025"
    initial_value="1.57"
    layout="topleft"
    label_width="100"
    label="View angle"
-   left_pad="30"
+   left="80"
    max_val="2.97"
    min_val="0.17"
    name="camera_fov"
@@ -62,21 +85,38 @@
   height="10"
   left="80"
   name="heading2"
-  width="270"
+  width="200"
   top_pad="5">
     Automatic position for:
   </text>
+
+  <spinner
+   control_name="CameraOpacity"
+   decimal_digits="1"
+   follows="top|left|right"
+   height="24"
+   max_val="1.0"
+   min_val="0.0"
+   increment="0.1"
+   initial_value="1.0"
+   label="Camera controls opacity:"
+   label_width="180"
+   layout="topleft"
+   top_pad="-10"
+   left_pad="10"
+   width="220" />
+
   <check_box
      control_name="EditCameraMovement"
      height="20"
      follows="left|top"
      label="Build/Edit"
      layout="topleft"
-     left_delta="30"
+     left="100"
      name="edit_camera_movement"
      tool_tip="Use automatic camera positioning when entering and exiting edit mode"
      width="280"
-     top_pad="5" />
+     top_pad="-10" />
   <check_box
    control_name="AppearanceCameraMovement"
    follows="left|top"
@@ -86,16 +126,68 @@
    name="appearance_camera_movement"
    tool_tip="Use automatic camera positioning while in edit mode"
    width="242" />
+
+  <button
+    follows="top|left"
+    height="23"
+    label="Save settings as a preset..."
+    layout="topleft"
+    left="30"
+    name="PrefCameraSaveButton"
+    top_pad="10"
+    width="200">
+    <button.commit_callback
+      function="Pref.PrefSave"
+      parameter="camera" />
+  </button>
+
+  <button
+    follows="top|left"
+    height="23"
+    label="Load preset..."
+    layout="topleft"
+    left_pad="10"
+    name="PrefCameraLoadButton"
+    top_delta="0"
+    width="115">
+    <button.commit_callback
+      function="Pref.PrefLoad"
+	  parameter="camera"/>
+  </button>
+
+  <button
+    follows="top|left"
+    height="23"
+    label="Delete preset..."
+    layout="topleft"
+    left_pad="10"
+    name="PrefCameraDeleteButton"
+    top_delta="0"
+    width="115">
+    <button.commit_callback
+      function="Pref.PrefDelete"
+	  parameter="camera"/>
+  </button>
+
+  <view_border
+    bevel_style="in"
+    follows="left|top|right"
+    height="0"
+    layout="topleft"
+    left="10"
+    top_pad="5"
+    width="500"/>
+
   <icon
-	 follows="left|top"
-	 height="18"
-	 image_name="Move_Walk_Off"
+   follows="left|top"
+   height="18"
+   image_name="Move_Walk_Off"
    layout="topleft"
-	 name="avatar_icon"
-	 mouse_opaque="false"
-	 visible="true"
-	 width="18"
-   top_pad="10"
+   name="avatar_icon"
+   mouse_opaque="false"
+   visible="true"
+   width="18"
+   top_pad="4"
    left="30" />
   <text
    follows="left|top"
@@ -264,10 +356,11 @@
    label="Other Devices"
    left="30"
    name="joystick_setup_button"
-   top="30"
+   top_pad="5"
    width="155">
     <button.commit_callback
      function="Floater.Show"
      parameter="pref_joystick" />
   </button>
+
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_presets_camera_pulldown.xml b/indra/newview/skins/default/xui/en/panel_presets_camera_pulldown.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dc3727075161442b2f10155e4032043baa61209f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_presets_camera_pulldown.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_opaque="true"
+ background_visible="true"
+ bg_opaque_image="Volume_Background"
+ bg_alpha_image="Volume_Background"
+ border_visible="false"
+ border="false"
+ chrome="true"
+ follows="bottom"
+ height="155"
+ layout="topleft"
+ name="presets_camera_pulldown"
+ width="225">
+  <text
+    type="string"
+    length="1"
+    follows="left|top"
+    height="12"
+    layout="topleft"
+    top="4"
+    left_delta="5"
+    font.style="BOLD"
+    name="Camera Presets"
+    width="120">
+      Camera Presets
+  </text>
+  <scroll_list
+    follows="left|top"
+    layout="topleft"
+    column_padding="0"
+    height="100"
+    width="215"
+    draw_heading="false"
+    draw_stripes="false"
+    bg_stripe_color="0.25 0.25 0.25 0.25"
+    top_delta="15"
+    left_delta="0"
+    name="preset_camera_list">
+    <scroll_list.columns
+      name="icon"
+      width="16" />
+    <scroll_list.columns
+      relative_width="1"
+      name="preset_name" />
+      <scroll_list.commit_callback
+      function="PresetsCamera.RowClick" />
+  </scroll_list>
+  <view_border
+    bevel_style="none"
+    follows="top|left"
+    height="0"
+    layout="topleft"
+    left="5"
+    name="horiz_separator"
+    top_delta="105"
+    width="215" />
+  <button
+    name="open_prefs_btn"
+    label="Open View Preferences"
+    tool_tip = "Bring up view preferences"
+    top_delta="5"
+    left="15"
+    height="20"
+    width="200">
+    <button.commit_callback
+      function="Presets.GoViewPrefs" />
+  </button>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 998f1ce59979d460145ba9747201e77f45cdda28..c6a42ea612c427b6b2f98a01e350c24b82134943 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -35,7 +35,7 @@
     </panel.string>
   <panel
     height="18"
-    left="-416"
+    left="-458"
     width="185"
     top="1"
     follows="right|top" 
@@ -108,10 +108,18 @@
     <icon
      follows="right|top"
      height="16"
-     image_name="Presets_Icon"
+     image_name="Presets_Icon_Camera"
      left_pad="8"
      top="2"
-     name="presets_icon"
+     name="presets_icon_camera"
+     width="18" />
+    <icon
+     follows="right|top"
+     height="16"
+     image_name="Presets_Icon_Graphic"
+     left_pad="8"
+     top="2"
+     name="presets_icon_graphic"
      width="18" />
     <button
      follows="right|top"