diff --git a/doc/contributions.txt b/doc/contributions.txt
index 2153e108882ae9445823a59db37ec683c5f5d388..7bbbf6430a52d84a7c080bc372caf750f71742e3 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -1517,6 +1517,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 e3bb36192c907c3b1efed33ee4442b84d6b52d06..abb043f4282b84df2cd878da7e829900ee8fce11 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1,5 +1,4 @@
 /** 
-
  * @file llfloater.cpp
  * @brief LLFloater base class
  *
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 63baed679345181f875abebe22f2f5419bc5b78b..7360bd76598799dc17e90fc46f2539c694ee8fe2 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -213,7 +213,8 @@ class LLUICtrl
 
 	virtual void	setColor(const LLColor4& color);
 
-	F32 			getCurrentTransparency();
+	// Ansariel: Changed to virtual. We might want to change the transparency ourself!
+	virtual F32	getCurrentTransparency();
 
 	void				setTransparencyType(ETypeTransparency type);
 	ETypeTransparency	getTransparencyType() const {return mTransparencyType;}
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index ccf4f3ddf50e66928b9a7d42cff491fa71b1bac3..80a414d00f69a993c15e2396273e1141c84b710f 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -40,6 +40,7 @@
 #include "v4coloru.h"
 #include "v4color.h"
 #include "v3color.h"
+#include "llquaternion.h"
 #include "llrect.h"
 #include "llxmltree.h"
 #include "llsdserialize.h"
@@ -125,6 +126,9 @@ bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b)
 	case TYPE_VEC3D:
 		result = LLVector3d(a) == LLVector3d(b);
 		break;
+	case TYPE_QUAT:
+		result = LLQuaternion(a) == LLQuaternion(b);
+		break;
 	case TYPE_RECT:
 		result = LLRect(a) == LLRect(b);
 		break;
@@ -361,6 +365,7 @@ const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32"
                                                              ,"String"
                                                              ,"Vector3"
                                                              ,"Vector3D"
+                                                             ,"Quaternion"
                                                              ,"Rect"
                                                              ,"Color4"
                                                              ,"Color3"
@@ -523,6 +528,11 @@ LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const L
 	return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist);
 }
 
+LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+	return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist);
+}
+
 LLControlVariable* LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 {
 	return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist);
@@ -600,6 +610,11 @@ LLVector3d LLControlGroup::getVector3d(const std::string& name)
 	return get<LLVector3d>(name);
 }
 
+LLQuaternion LLControlGroup::getQuaternion(const std::string& name)
+{
+	return get<LLQuaternion>(name);
+}
+
 LLRect LLControlGroup::getRect(const std::string& name)
 {
 	return get<LLRect>(name);
@@ -677,6 +692,11 @@ void LLControlGroup::setVector3d(const std::string& name, const LLVector3d &val)
 	set(name, val);
 }
 
+void LLControlGroup::setQuaternion(const std::string& name, const LLQuaternion &val)
+{
+	set(name, val);
+}
+
 void LLControlGroup::setRect(const std::string& name, const LLRect &val)
 {
 	set(name, val);
@@ -859,6 +879,16 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
 				validitems++;
 			}
 			break;
+		case TYPE_QUAT:
+			{
+				LLQuaternion quat;
+
+				child_nodep->getAttributeQuat("value", quat);
+
+				control->set(quat.getValue());
+				validitems++;
+			}
+			break;
 		case TYPE_RECT:
 			{
 				//RN: hack to support reading rectangles from a string
@@ -1201,6 +1231,11 @@ template <> eControlType get_control_type<LLVector3d>()
 	return TYPE_VEC3D; 
 }
 
+template <> eControlType get_control_type<LLQuaternion>()
+{
+	return TYPE_QUAT;
+}
+
 template <> eControlType get_control_type<LLRect>() 
 { 
 	return TYPE_RECT; 
@@ -1236,6 +1271,10 @@ template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in)
 { 
 	return in.getValue(); 
 }
+template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in)
+{
+	return in.getValue();
+}
 
 template <> LLSD convert_to_llsd<LLRect>(const LLRect& in) 
 { 
@@ -1348,6 +1387,18 @@ LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, cons
 	}
 }
 
+template<>
+LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, const std::string& control_name)
+{
+	if (type == TYPE_QUAT)
+		return (LLQuaternion)sd;
+	else
+	{
+		CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+		return LLQuaternion();
+	}
+}
+
 template<>
 LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name)
 {
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index de0d366492fcf475d60695955d8976e975fdd54a..f1369188963b94058bae5be9f1a06dbebf39a46c 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -67,6 +67,7 @@
 
 class LLVector3;
 class LLVector3d;
+class LLQuaternion;
 class LLColor4;
 class LLColor3;
 
@@ -80,6 +81,7 @@ typedef enum e_control_type
 	TYPE_STRING,
 	TYPE_VEC3,
 	TYPE_VEC3D,
+	TYPE_QUAT,
 	TYPE_RECT,
 	TYPE_COL4,
 	TYPE_COL3,
@@ -220,6 +222,7 @@ class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
 	LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 	LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment,  LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 	LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
+	LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 	LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 	LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 	LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
@@ -234,10 +237,10 @@ class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
 	
 	LLWString	getWString(const std::string& name);
 	LLVector3	getVector3(const std::string& name);
-	LLVector3d	getVector3d(const std::string& name);
+	LLVector3d	getVector3d(const std::string& name);	
 	LLRect		getRect(const std::string& name);
 	LLSD        getLLSD(const std::string& name);
-
+	LLQuaternion	getQuaternion(const std::string& name);
 
 	LLColor4	getColor(const std::string& name);
 	LLColor4	getColor4(const std::string& name);
@@ -270,6 +273,7 @@ class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
 	void	setString(const std::string&  name, const std::string& val);
 	void	setVector3(const std::string& name, const LLVector3 &val);
 	void	setVector3d(const std::string& name, const LLVector3d &val);
+	void	setQuaternion(const std::string& name, const LLQuaternion &val);
 	void	setRect(const std::string& name, const LLRect &val);
 	void	setColor4(const std::string& name, const LLColor4 &val);
 	void    setLLSD(const std::string& name, const LLSD& val);
@@ -436,7 +440,8 @@ template <> eControlType get_control_type<bool>();
 //template <> eControlType get_control_type<BOOL> () 
 template <> eControlType get_control_type<std::string>();
 template <> eControlType get_control_type<LLVector3>();
-template <> eControlType get_control_type<LLVector3d>(); 
+template <> eControlType get_control_type<LLVector3d>();
+template <> eControlType get_control_type<LLQuaternion>();
 template <> eControlType get_control_type<LLRect>();
 template <> eControlType get_control_type<LLColor4>();
 template <> eControlType get_control_type<LLColor3>();
@@ -444,7 +449,8 @@ template <> eControlType get_control_type<LLSD>();
 
 template <> LLSD convert_to_llsd<U32>(const U32& in);
 template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
-template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in); 
+template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
+template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in);
 template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
 template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
 template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in);
@@ -453,6 +459,7 @@ template<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlTy
 template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name);
 template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name);
 template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name);
+template<> LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, const std::string& control_name);
 template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name);
 template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name);
 template<> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name);
diff --git a/indra/llxml/llcontrolgroupreader.h b/indra/llxml/llcontrolgroupreader.h
index 6a27a65499ba226715f610c960127fb993129a1d..fe77d33fc420793e1f725303bd2c5b78902cab5d 100644
--- a/indra/llxml/llcontrolgroupreader.h
+++ b/indra/llxml/llcontrolgroupreader.h
@@ -65,6 +65,7 @@ class LLControlGroupReader
 	virtual void		setString(const std::string&  name, const std::string& val) {}
 	virtual void		setVector3(const std::string& name, const LLVector3 &val) {}
 	virtual void		setVector3d(const std::string& name, const LLVector3d &val) {}
+	virtual void		setQuaternion(const std::string& name, const LLQuaternion &val) {}
 	virtual void		setRect(const std::string& name, const LLRect &val) {}
 	virtual void		setColor4(const std::string& name, const LLColor4 &val) {}
 	virtual void    	setLLSD(const std::string& name, const LLSD& val) {}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index c9d5fb89ba983c764174268c33ceafbfd2f6eeb6..f76012bdfa1284bf1fba8b0f2124f5d9924e55e4 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -228,6 +228,7 @@ set(viewer_SOURCE_FILES
     llfloaterbuycurrencyhtml.cpp
     llfloaterbuyland.cpp
     llfloatercamera.cpp
+    llfloatercamerapresets.cpp
     llfloaterchatvoicevolume.cpp
     llfloatercolorpicker.cpp
     llfloaterconversationlog.cpp
@@ -288,12 +289,14 @@ set(viewer_SOURCE_FILES
     llfloaterperms.cpp
     llfloaterpostprocess.cpp
     llfloaterpreference.cpp
+    llfloaterpreferenceviewadvanced.cpp
     llfloaterpreviewtrash.cpp
     llfloaterproperties.cpp
     llfloaterregiondebugconsole.cpp
     llfloaterregioninfo.cpp
     llfloaterreporter.cpp
     llfloaterregionrestarting.cpp
+    llfloatersavecamerapreset.cpp
     llfloatersaveprefpreset.cpp
     llfloatersceneloadstats.cpp
     llfloaterscriptdebug.cpp
@@ -481,6 +484,7 @@ set(viewer_SOURCE_FILES
     llpanelplaceprofile.cpp
     llpanelplaces.cpp
     llpanelplacestab.cpp
+    llpanelpresetscamerapulldown.cpp
     llpanelpresetspulldown.cpp
     llpanelprimmediacontrols.cpp
     llpanelprofile.cpp
@@ -494,6 +498,7 @@ set(viewer_SOURCE_FILES
     llpaneltiptoast.cpp
     llpanelvoiceeffect.cpp
     llpaneltopinfobar.cpp
+    llpanelpulldown.cpp
     llpanelvoicedevicesettings.cpp
     llpanelvolume.cpp
     llpanelvolumepulldown.cpp
@@ -852,6 +857,7 @@ set(viewer_HEADER_FILES
     llfloaterbuycurrency.h
     llfloaterbuycurrencyhtml.h
     llfloaterbuyland.h
+    llfloatercamerapresets.h
     llfloatercamera.h
     llfloaterchatvoicevolume.h
     llfloatercolorpicker.h
@@ -916,12 +922,14 @@ set(viewer_HEADER_FILES
     llfloaterperms.h
     llfloaterpostprocess.h
     llfloaterpreference.h
+    llfloaterpreferenceviewadvanced.h
     llfloaterpreviewtrash.h
     llfloaterproperties.h
     llfloaterregiondebugconsole.h
     llfloaterregioninfo.h
     llfloaterreporter.h
     llfloaterregionrestarting.h
+    llfloatersavecamerapreset.h
     llfloatersaveprefpreset.h
     llfloatersceneloadstats.h
     llfloaterscriptdebug.h
@@ -1099,12 +1107,14 @@ set(viewer_HEADER_FILES
     llpanelplaceprofile.h
     llpanelplaces.h
     llpanelplacestab.h
+    llpanelpresetscamerapulldown.h
     llpanelpresetspulldown.h
     llpanelprimmediacontrols.h
     llpanelprofile.h
     llpanelsnapshot.h
     llpanelteleporthistory.h
     llpaneltiptoast.h
+    llpanelpulldown.h
     llpanelvoicedevicesettings.h
     llpanelvoiceeffect.h
     llpaneltopinfobar.h
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index a4c853ea2ea69dbd548168a6823f26d772f27f2c..133cad286fdf619d1cbbb26931c01f4e180b36a4 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.4.2
+6.4.3
diff --git a/indra/newview/app_settings/camera/Front.xml b/indra/newview/app_settings/camera/Front.xml
new file mode 100644
index 0000000000000000000000000000000000000000..39f44e11a841a8c420096924cfaf5529ea8e109a
--- /dev/null
+++ b/indra/newview/app_settings/camera/Front.xml
@@ -0,0 +1,142 @@
+<llsd>
+    <map>
+    <key>AppearanceCameraMovement</key>
+        <map>
+        <key>Comment</key>
+            <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>1</integer>
+        </map>
+    <key>AvatarSitRotation</key>
+    <map>
+        <key>Comment</key>
+        <string>Avatar real sitting rotation used in preset</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>LLSD</string>
+        <key>Value</key>
+        <array>
+          <real>0</real>
+          <real>0</real>
+          <real>0</real>
+          <real>1</real>
+        </array>
+    </map>
+    <key>CameraAngle</key>
+        <map>
+        <key>Comment</key>
+            <string>Camera field of view angle (Radians)</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>1.047197551</real>
+        </map>
+    <key>CameraOffsetBuild</key>
+        <map>
+        <key>Comment</key>
+            <string>Default camera position relative to focus point when entering build mode</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Vector3</string>
+        <key>Value</key>
+            <array>
+                <real>-6</real>
+                <real>0</real>
+                <real>6</real>
+            </array>
+        </map>
+    <key>CameraOffsetRearView</key>
+        <map>
+        <key>Comment</key>
+            <string>Initial camera offset from avatar in Front View</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Vector3</string>
+        <key>Value</key>
+            <array>
+                <real>2.2</real>
+                <real>0.0</real>
+                <real>0.0</real>
+            </array>
+        </map>
+    <key>CameraOffsetScale</key>
+        <map>
+        <key>Comment</key>
+            <string>Scales the default offset</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>1</real>
+        </map>
+    <key>CameraZoomFraction</key>
+        <map>
+        <key>Comment</key>
+            <string>Mousewheel driven fraction of zoom</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>0.90322577953338623</real>
+        </map>
+    <key>EditCameraMovement</key>
+        <map>
+        <key>Comment</key>
+            <string>When entering build mode, camera moves up above avatar</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>0</integer>
+        </map>
+    <key>FocusOffsetRearView</key>
+        <map>
+        <key>Comment</key>
+            <string>Initial focus point offset relative to avatar for the camera preset Front View (x-axis is forward)</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Vector3D</string>
+        <key>Value</key>
+            <array>
+                <real>0.0</real>
+                <real>0.0</real>
+                <real>0.0</real>
+            </array>
+        </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>Default</string>
+        </map>
+    <key>TrackFocusObject</key>
+        <map>
+        <key>Comment</key>
+            <string>Camera tracks last object zoomed on</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>1</integer>
+        </map>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/camera/Rear.xml b/indra/newview/app_settings/camera/Rear.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8dc36353ce20a3ea3eaa6405c45c07b043f33956
--- /dev/null
+++ b/indra/newview/app_settings/camera/Rear.xml
@@ -0,0 +1,142 @@
+<llsd>
+    <map>
+    <key>AppearanceCameraMovement</key>
+        <map>
+        <key>Comment</key>
+            <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>1</integer>
+        </map>
+    <key>AvatarSitRotation</key>
+    <map>
+        <key>Comment</key>
+        <string>Avatar real sitting rotation used in preset</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>LLSD</string>
+        <key>Value</key>
+        <array>
+          <real>0</real>
+          <real>0</real>
+          <real>0</real>
+          <real>1</real>
+        </array>
+    </map>
+    <key>CameraAngle</key>
+        <map>
+        <key>Comment</key>
+            <string>Camera field of view angle (Radians)</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>1.047197551</real>
+        </map>
+    <key>CameraOffsetBuild</key>
+        <map>
+        <key>Comment</key>
+            <string>Default camera position relative to focus point when entering build mode</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Vector3</string>
+        <key>Value</key>
+            <array>
+                <real>-6</real>
+                <real>0</real>
+                <real>6</real>
+            </array>
+        </map>
+    <key>CameraOffsetRearView</key>
+        <map>
+        <key>Comment</key>
+            <string>Initial camera offset from avatar in Rear View</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Vector3</string>
+        <key>Value</key>
+            <array>
+                <real>-3</real>
+                <real>0</real>
+                <real>0.75</real>
+            </array>
+        </map>
+    <key>CameraOffsetScale</key>
+        <map>
+        <key>Comment</key>
+            <string>Scales the default offset</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>1</real>
+        </map>
+    <key>CameraZoomFraction</key>
+        <map>
+        <key>Comment</key>
+            <string>Mousewheel driven fraction of zoom</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>0.90322577953338623</real>
+        </map>
+    <key>EditCameraMovement</key>
+        <map>
+        <key>Comment</key>
+            <string>When entering build mode, camera moves up above avatar</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>0</integer>
+        </map>
+    <key>FocusOffsetRearView</key>
+        <map>
+        <key>Comment</key>
+            <string>Initial focus point offset relative to avatar for the camera preset Rear View (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>
+    <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>Default</string>
+        </map>
+    <key>TrackFocusObject</key>
+        <map>
+        <key>Comment</key>
+            <string>Camera tracks last object zoomed on</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>1</integer>
+        </map>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/camera/Side.xml b/indra/newview/app_settings/camera/Side.xml
new file mode 100644
index 0000000000000000000000000000000000000000..089ab93a8f67d3033b5a83586cf22d5441d4dbf9
--- /dev/null
+++ b/indra/newview/app_settings/camera/Side.xml
@@ -0,0 +1,142 @@
+<llsd>
+    <map>
+    <key>AppearanceCameraMovement</key>
+        <map>
+        <key>Comment</key>
+            <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>1</integer>
+        </map>
+    <key>AvatarSitRotation</key>
+    <map>
+        <key>Comment</key>
+        <string>Avatar real sitting rotation used in preset</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>LLSD</string>
+        <key>Value</key>
+        <array>
+          <real>0</real>
+          <real>0</real>
+          <real>0</real>
+          <real>1</real>
+        </array>
+    </map>
+    <key>CameraAngle</key>
+        <map>
+        <key>Comment</key>
+            <string>Camera field of view angle (Radians)</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>1.047197551</real>
+        </map>
+    <key>CameraOffsetBuild</key>
+        <map>
+        <key>Comment</key>
+            <string>Default camera position relative to focus point when entering build mode</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Vector3</string>
+        <key>Value</key>
+            <array>
+                <real>-6</real>
+                <real>0</real>
+                <real>6</real>
+            </array>
+        </map>
+    <key>CameraOffsetRearView</key>
+        <map>
+        <key>Comment</key>
+            <string>Initial camera offset from avatar in Side View</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Vector3</string>
+        <key>Value</key>
+            <array>
+                <real>-1.0</real>
+                <real>0.7</real>
+                <real>0.5</real>
+            </array>
+        </map>
+    <key>CameraOffsetScale</key>
+        <map>
+        <key>Comment</key>
+            <string>Scales the default offset</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>1</real>
+        </map>
+    <key>CameraZoomFraction</key>
+        <map>
+        <key>Comment</key>
+            <string>Mousewheel driven fraction of zoom</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>F32</string>
+        <key>Value</key>
+            <real>0.90322577953338623</real>
+        </map>
+    <key>EditCameraMovement</key>
+        <map>
+        <key>Comment</key>
+            <string>When entering build mode, camera moves up above avatar</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>0</integer>
+        </map>
+    <key>FocusOffsetRearView</key>
+        <map>
+        <key>Comment</key>
+            <string>Initial focus point offset relative to avatar for the camera preset Side View (x-axis is forward)</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Vector3D</string>
+        <key>Value</key>
+            <array>
+                <real>1.5</real>
+                <real>0.7</real>
+                <real>1.0</real>
+            </array>
+        </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>Default</string>
+        </map>
+    <key>TrackFocusObject</key>
+        <map>
+        <key>Comment</key>
+            <string>Camera tracks last object zoomed on</string>
+        <key>Persist</key>
+            <integer>1</integer>
+        <key>Type</key>
+            <string>Boolean</string>
+        <key>Value</key>
+            <integer>1</integer>
+        </map>
+    </map>
+</llsd>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 0cb9ee3aceb4970dd40047c06738f23069e323f5..86c6b409de113353789a9fbc7fe65a359b0519e9 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1510,6 +1510,21 @@
         <real>0.5</real>
       </array>
     </map>
+    <key>CameraOffsetCustomPreset</key>
+    <map>
+      <key>Comment</key>
+      <string>Initial camera offset from avatar for the custom camera preset</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>CameraOffsetScale</key>
     <map>
       <key>Comment</key>
@@ -1521,6 +1536,17 @@
       <key>Value</key>
       <real>1.0</real>
     </map>
+    <key>CameraZoomFraction</key>
+    <map>
+      <key>Comment</key>
+      <string>Mousewheel driven fraction of zoom</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>0.9</real>
+    </map>
     <key>CameraPosOnLogout</key>
     <map>
       <key>Comment</key>
@@ -1558,7 +1584,7 @@
       <key>Value</key>
       <real>1.0</real>
     </map>
-    <key>CameraPreset</key>
+    <key>CameraPreset</key>  <!-- deprecated (see SL-12429) -->
     <map>
       <key>Comment</key>
       <string>Preset camera position - view (0 - rear, 1 - front, 2 - group)</string>
@@ -4378,6 +4404,37 @@
         <real>1.0</real>
       </array>
     </map>
+    <key>FocusOffsetCustomPreset</key>
+    <map>
+      <key>Comment</key>
+      <string>Initial focus point offset relative to avatar for the custom camera preset (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>
+    <key>AvatarSitRotation</key>
+    <map>
+      <key>Comment</key>
+      <string>Avatar real sitting rotation used in preset</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>LLSD</string>
+      <key>Value</key>
+      <array>
+        <real>0</real>
+        <real>0</real>
+        <real>0</real>
+        <real>1</real>
+      </array>
+    </map>
     <key>FocusPosOnLogout</key>
     <map>
       <key>Comment</key>
@@ -16492,6 +16549,50 @@
       <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>Rear View</string>
+  </map>
+  <key>CameraPresetType</key>
+  <map>
+    <key>Comment</key>
+    <string>Preset camera position - view (0 - rear, 1 - front, 2 - group, 3 - custom)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <integer>0</integer>
+   </map>
+  <key>HoverHeightAffectsCamera</key>
+  <map>
+    <key>Comment</key>
+    <string>Camera view is affected by Hover Height setting</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+   </map>
     <key>CefVerboseLog</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 85b7d7b06f3594e750cdb6e73303ac2c57a988a2..9e65409256890db2d751144f91fe990260a42caa 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -184,6 +184,9 @@ LLAgentCamera::LLAgentCamera() :
 	clearGeneralKeys();
 	clearOrbitKeys();
 	clearPanKeys();
+
+	resetPanDiff();
+	resetOrbitDiff();
 }
 
 // Requires gSavedSettings to be initialized.
@@ -205,15 +208,10 @@ void LLAgentCamera::init()
 
 	mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild"));
 	
-	mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPreset");
-
-	mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView");
-	mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView");
-	mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView");
+	mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType");
 
-	mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView");
-	mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView");
-	mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView");
+	mCameraOffsetInitial = gSavedSettings.getControl("CameraOffsetRearView");
+	mFocusOffsetInitial = gSavedSettings.getControl("FocusOffsetRearView");
 
 	mCameraCollidePlane.clearVec();
 	mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
@@ -353,7 +351,8 @@ void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera)
 
 		mCameraFOVZoomFactor = 0.f;
 	}
-
+	resetPanDiff();
+	resetOrbitDiff();
 	mHUDTargetZoom = 1.f;
 }
 
@@ -723,7 +722,7 @@ BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance)
 	return TRUE;
 }
 
-F32 LLAgentCamera::getCameraZoomFraction()
+F32 LLAgentCamera::getCameraZoomFraction(bool get_third_person)
 {
 	// 0.f -> camera zoomed all the way out
 	// 1.f -> camera zoomed all the way in
@@ -733,7 +732,7 @@ F32 LLAgentCamera::getCameraZoomFraction()
 		// already [0,1]
 		return mHUDTargetZoom;
 	}
-	else if (mFocusOnAvatar && cameraThirdPerson())
+	else if (get_third_person || (mFocusOnAvatar && cameraThirdPerson()))
 	{
 		return clamp_rescale(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION, 1.f, 0.f);
 	}
@@ -795,13 +794,16 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction)
 
 		if (mFocusObject.notNull())
 		{
-			if (mFocusObject->isAvatar())
+			if (mFocusObject.notNull())
 			{
-				min_zoom = AVATAR_MIN_ZOOM;
-			}
-			else
-			{
-				min_zoom = OBJECT_MIN_ZOOM;
+				if (mFocusObject->isAvatar())
+				{
+					min_zoom = AVATAR_MIN_ZOOM;
+				}
+				else
+				{
+					min_zoom = OBJECT_MIN_ZOOM;
+				}
 			}
 		}
 
@@ -835,6 +837,7 @@ void LLAgentCamera::cameraOrbitAround(const F32 radians)
 	}
 	else
 	{
+		mOrbitAroundRadians += radians;
 		mCameraFocusOffsetTarget.rotVec(radians, 0.f, 0.f, 1.f);
 		
 		cameraZoomIn(1.f);
@@ -866,12 +869,34 @@ void LLAgentCamera::cameraOrbitOver(const F32 angle)
 		LLVector3d left_axis;
 		left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis());
 		F32 new_angle = llclamp(angle_from_up - angle, 1.f * DEG_TO_RAD, 179.f * DEG_TO_RAD);
+		mOrbitOverAngle += angle_from_up - new_angle;
 		mCameraFocusOffsetTarget.rotVec(angle_from_up - new_angle, left_axis);
 
 		cameraZoomIn(1.f);
 	}
 }
 
+void LLAgentCamera::resetCameraOrbit()
+{
+	LLVector3 camera_offset_unit(mCameraFocusOffsetTarget);
+	camera_offset_unit.normalize();
+
+	LLVector3d left_axis;
+	left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis());
+	mCameraFocusOffsetTarget.rotVec(-mOrbitOverAngle, left_axis);
+	
+	mCameraFocusOffsetTarget.rotVec(-mOrbitAroundRadians, 0.f, 0.f, 1.f);
+
+	cameraZoomIn(1.f);
+	resetOrbitDiff();
+}
+
+void LLAgentCamera::resetOrbitDiff()
+{
+	mOrbitAroundRadians = 0;
+	mOrbitOverAngle = 0;
+}
+
 //-----------------------------------------------------------------------------
 // cameraZoomIn()
 //-----------------------------------------------------------------------------
@@ -1010,6 +1035,8 @@ void LLAgentCamera::cameraPanIn(F32 meters)
 	LLVector3d at_axis;
 	at_axis.setVec(LLViewerCamera::getInstance()->getAtAxis());
 
+	mPanFocusDiff += meters * at_axis;
+
 	mFocusTargetGlobal += meters * at_axis;
 	mFocusGlobal = mFocusTargetGlobal;
 	// don't enforce zoom constraints as this is the only way for users to get past them easily
@@ -1026,6 +1053,8 @@ void LLAgentCamera::cameraPanLeft(F32 meters)
 	LLVector3d left_axis;
 	left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis());
 
+	mPanFocusDiff += meters * left_axis;
+
 	mFocusTargetGlobal += meters * left_axis;
 	mFocusGlobal = mFocusTargetGlobal;
 
@@ -1046,6 +1075,8 @@ void LLAgentCamera::cameraPanUp(F32 meters)
 	LLVector3d up_axis;
 	up_axis.setVec(LLViewerCamera::getInstance()->getUpAxis());
 
+	mPanFocusDiff += meters * up_axis;
+
 	mFocusTargetGlobal += meters * up_axis;
 	mFocusGlobal = mFocusTargetGlobal;
 
@@ -1058,6 +1089,26 @@ void LLAgentCamera::cameraPanUp(F32 meters)
 	mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal();
 }
 
+void LLAgentCamera::resetCameraPan()
+{
+	mFocusTargetGlobal -= mPanFocusDiff;
+
+	mFocusGlobal = mFocusTargetGlobal;
+	mCameraSmoothingStop = true;
+
+	cameraZoomIn(1.f);
+	updateFocusOffset();
+
+	mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal();
+
+	resetPanDiff();
+}
+
+void LLAgentCamera::resetPanDiff()
+{
+	mPanFocusDiff.clear();
+}
+
 //-----------------------------------------------------------------------------
 // updateLookAt()
 //-----------------------------------------------------------------------------
@@ -1609,7 +1660,7 @@ LLVector3d LLAgentCamera::calcThirdPersonFocusOffset()
 		agent_rot *= ((LLViewerObject*)(gAgentAvatarp->getParent()))->getRenderRotation();
 	}
 
-	focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial[mCameraPreset]->get(), TYPE_VEC3D, "");
+	focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, "");
 	return focus_offset * agent_rot;
 }
 
@@ -1684,7 +1735,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 	F32			camera_land_height;
 	LLVector3d	frame_center_global = !isAgentAvatarValid() ? 
 		gAgent.getPositionGlobal() :
-		gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot->getWorldPosition());
+		gAgent.getPosGlobalFromAgent(getAvatarRootPosition());
 	
 	BOOL		isConstrained = FALSE;
 	LLVector3d	head_offset;
@@ -1758,7 +1809,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 				at_axis.mV[VZ] = 0.f;
 				at_axis.normalize();
 				gAgent.resetAxes(at_axis * ~parent_rot);
-
+				
 				local_camera_offset = local_camera_offset * gAgent.getFrameAgent().getQuaternion() * parent_rot;
 			}
 			else
@@ -1939,9 +1990,38 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 }
 
 
+LLVector3 LLAgentCamera::getCurrentCameraOffset()
+{
+	return (LLViewerCamera::getInstance()->getOrigin() - getAvatarRootPosition() - mThirdPersonHeadOffset) * ~getCurrentAvatarRotation();
+}
+
+LLVector3d LLAgentCamera::getCurrentFocusOffset()
+{
+	return (mFocusTargetGlobal - gAgent.getPositionGlobal()) * ~getCurrentAvatarRotation();
+}
+
+LLQuaternion LLAgentCamera::getCurrentAvatarRotation()
+{
+	LLViewerObject* sit_object = (LLViewerObject*)gAgentAvatarp->getParent();
+	
+	LLQuaternion av_rot = gAgent.getFrameAgent().getQuaternion();
+	LLQuaternion obj_rot = sit_object ? sit_object->getRenderRotation() : LLQuaternion::DEFAULT;
+	return av_rot * obj_rot;
+}
+
+bool LLAgentCamera::isJoystickCameraUsed()
+{
+	return ((mOrbitAroundRadians != 0) || (mOrbitOverAngle != 0) || !mPanFocusDiff.isNull());
+}
+
 LLVector3 LLAgentCamera::getCameraOffsetInitial()
 {
-	return convert_from_llsd<LLVector3>(mCameraOffsetInitial[mCameraPreset]->get(), TYPE_VEC3, "");
+	return convert_from_llsd<LLVector3>(mCameraOffsetInitial->get(), TYPE_VEC3, "");
+}
+
+LLVector3d LLAgentCamera::getFocusOffsetInitial()
+{
+	return convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, "");
 }
 
 F32 LLAgentCamera::getCameraMaxZoomDistance()
@@ -1952,6 +2032,12 @@ F32 LLAgentCamera::getCameraMaxZoomDistance()
                  LLWorld::getInstance()->getRegionWidthInMeters() - CAMERA_FUDGE_FROM_OBJECT);
 }
 
+LLVector3 LLAgentCamera::getAvatarRootPosition()
+{
+    static LLCachedControl<bool> use_hover_height(gSavedSettings, "HoverHeightAffectsCamera");
+    return use_hover_height ? gAgentAvatarp->mRoot->getWorldPosition() : gAgentAvatarp->mRoot->getWorldPosition() - gAgentAvatarp->getHoverOffset();
+
+}
 //-----------------------------------------------------------------------------
 // handleScrollWheel()
 //-----------------------------------------------------------------------------
@@ -2231,15 +2317,7 @@ void LLAgentCamera::changeCameraToThirdPerson(BOOL animate)
 	}
 
 	// Remove any pitch from the avatar
-	if (isAgentAvatarValid() && gAgentAvatarp->getParent())
-	{
-		LLQuaternion obj_rot = ((LLViewerObject*)gAgentAvatarp->getParent())->getRenderRotation();
-		at_axis = LLViewerCamera::getInstance()->getAtAxis();
-		at_axis.mV[VZ] = 0.f;
-		at_axis.normalize();
-		gAgent.resetAxes(at_axis * ~obj_rot);
-	}
-	else
+	if (!isAgentAvatarValid() || !gAgentAvatarp->getParent())
 	{
 		at_axis = gAgent.getFrameAgent().getAtAxis();
 		at_axis.mV[VZ] = 0.f;
@@ -2338,7 +2416,10 @@ void LLAgentCamera::switchCameraPreset(ECameraPreset preset)
 
 	mCameraPreset = preset;
 
-	gSavedSettings.setU32("CameraPreset", mCameraPreset);
+	resetPanDiff();
+	resetOrbitDiff();
+
+	gSavedSettings.setU32("CameraPresetType", mCameraPreset);
 }
 
 
@@ -2583,7 +2664,7 @@ void LLAgentCamera::setSitCamera(const LLUUID &object_id, const LLVector3 &camer
 //-----------------------------------------------------------------------------
 // setFocusOnAvatar()
 //-----------------------------------------------------------------------------
-void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate)
+void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate, BOOL reset_axes)
 {
 	if (focus_on_avatar != mFocusOnAvatar)
 	{
@@ -2600,22 +2681,14 @@ void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate)
 	//RN: when focused on the avatar, we're not "looking" at it
 	// looking implies intent while focusing on avatar means
 	// you're just walking around with a camera on you...eesh.
-	if (!mFocusOnAvatar && focus_on_avatar)
+	if (!mFocusOnAvatar && focus_on_avatar && reset_axes)
 	{
 		setFocusGlobal(LLVector3d::zero);
 		mCameraFOVZoomFactor = 0.f;
 		if (mCameraMode == CAMERA_MODE_THIRD_PERSON)
 		{
 			LLVector3 at_axis;
-			if (isAgentAvatarValid() && gAgentAvatarp->getParent())
-			{
-				LLQuaternion obj_rot = ((LLViewerObject*)gAgentAvatarp->getParent())->getRenderRotation();
-				at_axis = LLViewerCamera::getInstance()->getAtAxis();
-				at_axis.mV[VZ] = 0.f;
-				at_axis.normalize();
-				gAgent.resetAxes(at_axis * ~obj_rot);
-			}
-			else
+			if (!isAgentAvatarValid() || !gAgentAvatarp->getParent())
 			{
 				at_axis = LLViewerCamera::getInstance()->getAtAxis();
 				at_axis.mV[VZ] = 0.f;
@@ -2763,6 +2836,17 @@ BOOL LLAgentCamera::setPointAt(EPointAtType target_type, LLViewerObject *object,
 	return mPointAt->setPointAt(target_type, object, position);
 }
 
+void LLAgentCamera::rotateToInitSitRot()
+{
+	gAgent.rotate(~gAgent.getFrameAgent().getQuaternion());
+	gAgent.rotate(mInitSitRot);
+}
+
+void LLAgentCamera::resetCameraZoomFraction()
+{ 
+	mCameraZoomFraction = INITIAL_ZOOM_FRACTION; 
+}
+
 ELookAtType LLAgentCamera::getLookAtType()
 {
 	if (mLookAt) 
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index a4bc8434b0c982892ff99b8710e6a4d721ed9d4f..ec1ed433d7cd9b26564b7c719041db24c7ffa3ee 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_CUSTOM
 };
 
 //------------------------------------------------------------------------
@@ -109,20 +112,32 @@ class LLAgentCamera
 	//--------------------------------------------------------------------
 public:
 	void switchCameraPreset(ECameraPreset preset);
-private:
 	/** Determines default camera offset depending on the current camera preset */
 	LLVector3 getCameraOffsetInitial();
+	/** Determines default focus offset depending on the current camera preset */
+	LLVector3d getFocusOffsetInitial();
+
+	LLVector3 getCurrentCameraOffset();
+	LLVector3d getCurrentFocusOffset();
+	LLQuaternion getCurrentAvatarRotation();
+	bool isJoystickCameraUsed();
+	void setInitSitRot(LLQuaternion sit_rot) { mInitSitRot = sit_rot; };
+	void rotateToInitSitRot();
+
+private:
 	/** Determines maximum camera distance from target for mouselook, opposite to LAND_MIN_ZOOM */
 	F32 getCameraMaxZoomDistance();
 
 	/** Camera preset in Third Person Mode */
 	ECameraPreset mCameraPreset; 
 
-	/** Initial camera offsets */
-	std::map<ECameraPreset, LLPointer<LLControlVariable> > mCameraOffsetInitial;
+	/** Initial camera offset */
+	LLPointer<LLControlVariable> mCameraOffsetInitial;
+
+	/** Initial focus offset */
+	LLPointer<LLControlVariable> mFocusOffsetInitial;
 
-	/** Initial focus offsets */
-	std::map<ECameraPreset, LLPointer<LLControlVariable> > mFocusOffsetInitial;
+	LLQuaternion mInitSitRot;
 
 	//--------------------------------------------------------------------
 	// Position
@@ -137,6 +152,8 @@ class LLAgentCamera
 	F32				getCurrentCameraBuildOffset() 	{ return (F32)mCameraFocusOffset.length(); }
 	void			clearCameraLag() { mCameraLag.clearVec(); }
 private:
+	LLVector3		getAvatarRootPosition();
+
 	F32				mCurrentCameraDistance;	 		// Current camera offset from avatar
 	F32				mTargetCameraDistance;			// Target camera offset from avatar
 	F32				mCameraFOVZoomFactor;			// Amount of fov zoom applied to camera when zeroing in on an object
@@ -204,7 +221,7 @@ class LLAgentCamera
 	void			validateFocusObject();
 	void			setFocusGlobal(const LLPickInfo& pick);
 	void			setFocusGlobal(const LLVector3d &focus, const LLUUID &object_id = LLUUID::null);
-	void			setFocusOnAvatar(BOOL focus, BOOL animate);
+	void			setFocusOnAvatar(BOOL focus, BOOL animate, BOOL reset_axes = TRUE);
 	void			setCameraPosAndFocusGlobal(const LLVector3d& pos, const LLVector3d& focus, const LLUUID &object_id);
 	void			clearFocusObject();
 	void			setFocusObject(LLViewerObject* object);
@@ -256,26 +273,31 @@ class LLAgentCamera
 	void			cameraOrbitAround(const F32 radians);	// Rotate camera CCW radians about build focus point
 	void			cameraOrbitOver(const F32 radians);		// Rotate camera forward radians over build focus point
 	void			cameraOrbitIn(const F32 meters);		// Move camera in toward build focus point
-
+	void			resetCameraOrbit();
+	void			resetOrbitDiff();
 	//--------------------------------------------------------------------
 	// Zoom
 	//--------------------------------------------------------------------
 public:
-	void			handleScrollWheel(S32 clicks); 			// Mousewheel driven zoom
-	void			cameraZoomIn(const F32 factor);			// Zoom in by fraction of current distance
-	F32				getCameraZoomFraction();				// Get camera zoom as fraction of minimum and maximum zoom
-	void			setCameraZoomFraction(F32 fraction);	// Set camera zoom as fraction of minimum and maximum zoom
+	void			handleScrollWheel(S32 clicks); 							// Mousewheel driven zoom
+	void			cameraZoomIn(const F32 factor);							// Zoom in by fraction of current distance
+	F32				getCameraZoomFraction(bool get_third_person = false);	// Get camera zoom as fraction of minimum and maximum zoom
+	void			setCameraZoomFraction(F32 fraction);					// Set camera zoom as fraction of minimum and maximum zoom
 	F32				calcCameraFOVZoomFactor();
 	F32				getAgentHUDTargetZoom();
 
+	void			resetCameraZoomFraction();
+	F32				getCurrentCameraZoomFraction() { return mCameraZoomFraction; }
+
 	//--------------------------------------------------------------------
 	// Pan
 	//--------------------------------------------------------------------
 public:
 	void			cameraPanIn(const F32 meters);
 	void			cameraPanLeft(const F32 meters);
-	void			cameraPanUp(const F32 meters);
-	
+	void			cameraPanUp(const F32 meters);	
+	void			resetCameraPan();
+	void			resetPanDiff();
 	//--------------------------------------------------------------------
 	// View
 	//--------------------------------------------------------------------
@@ -362,6 +384,9 @@ class LLAgentCamera
 	F32				mOrbitInKey;
 	F32				mOrbitOutKey;
 
+	F32				mOrbitAroundRadians;
+	F32				mOrbitOverAngle;
+
 	//--------------------------------------------------------------------
 	// Pan
 	//--------------------------------------------------------------------
@@ -389,6 +414,8 @@ class LLAgentCamera
 	F32				mPanInKey;
 	F32				mPanOutKey;
 
+	LLVector3d		mPanFocusDiff;
+
 /**                    Keys
  **                                                                            **
  *******************************************************************************/
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index f3406d93bb11ed388397ac50f1ad032d34d73a9b..d574f1433f764e051d6195df8b3fe0d069dc0b9c 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -34,6 +34,7 @@
 // Viewer includes
 #include "llagent.h"
 #include "llagentcamera.h"
+#include "llpresetsmanager.h"
 #include "lljoystickbutton.h"
 #include "llviewercontrol.h"
 #include "llviewercamera.h"
@@ -42,6 +43,8 @@
 #include "llslider.h"
 #include "llfirstuse.h"
 #include "llhints.h"
+#include "lltabcontainer.h"
+#include "llvoavatarself.h"
 
 static LLDefaultChildRegistry::Register<LLPanelCameraItem> r("panel_camera_item");
 
@@ -52,7 +55,6 @@ const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed
 #define ORBIT "cam_rotate_stick"
 #define PAN "cam_track_stick"
 #define ZOOM "zoom"
-#define PRESETS "preset_views_list"
 #define CONTROLS "controls"
 
 bool LLFloaterCamera::sFreeCamera = false;
@@ -269,13 +271,7 @@ void LLFloaterCamera::onAvatarEditingAppearance(bool editing)
 
 void LLFloaterCamera::handleAvatarEditingAppearance(bool editing)
 {
-	//camera presets (rear, front, etc.)
-	getChildView("preset_views_list")->setEnabled(!editing);
-	getChildView("presets_btn")->setEnabled(!editing);
 
-	//camera modes (object view, mouselook view)
-	getChildView("camera_modes_list")->setEnabled(!editing);
-	getChildView("avatarview_btn")->setEnabled(!editing);
 }
 
 void LLFloaterCamera::update()
@@ -322,6 +318,8 @@ void LLFloaterCamera::onOpen(const LLSD& key)
 	else
 		toPrevMode();
 	mClosed = FALSE;
+
+	populatePresetCombo();
 }
 
 void LLFloaterCamera::onClose(bool app_quitting)
@@ -353,6 +351,8 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val)
 {
 	LLHints::getInstance()->registerHintTarget("view_popup", getHandle());
 	mCommitCallbackRegistrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
+	mCommitCallbackRegistrar.add("CameraPresets.Save", boost::bind(&LLFloaterCamera::onSavePreset, this));
+	mCommitCallbackRegistrar.add("CameraPresets.ShowPresetsList", boost::bind(&LLFloaterReg::showInstance, "camera_presets", LLSD(), FALSE));
 }
 
 // virtual
@@ -363,10 +363,14 @@ BOOL LLFloaterCamera::postBuild()
 	mRotate = getChild<LLJoystickCameraRotate>(ORBIT);
 	mZoom = findChild<LLPanelCameraZoom>(ZOOM);
 	mTrack = getChild<LLJoystickCameraTrack>(PAN);
+	mPresetCombo = getChild<LLComboBox>("preset_combo");
+
+	getChild<LLTextBox>("precise_ctrs_label")->setShowCursorHand(false);
+	getChild<LLTextBox>("precise_ctrs_label")->setSoundFlags(LLView::MOUSE_UP);
+	getChild<LLTextBox>("precise_ctrs_label")->setClickedCallback(boost::bind(&LLFloaterReg::showInstance, "prefs_view_advanced", LLSD(), FALSE));
 
-	assignButton2Mode(CAMERA_CTRL_MODE_MODES,			"avatarview_btn");
-	assignButton2Mode(CAMERA_CTRL_MODE_PAN,				"pan_btn");
-	assignButton2Mode(CAMERA_CTRL_MODE_PRESETS,		"presets_btn");
+	mPresetCombo->setCommitCallback(boost::bind(&LLFloaterCamera::onCustomPresetSelected, this));
+	LLPresetsManager::getInstance()->setPresetListChangeCameraCallback(boost::bind(&LLFloaterCamera::populatePresetCombo, this));
 
 	update();
 
@@ -376,6 +380,15 @@ BOOL LLFloaterCamera::postBuild()
 	return LLFloater::postBuild();
 }
 
+F32	LLFloaterCamera::getCurrentTransparency()
+{
+
+	static LLCachedControl<F32> camera_opacity(gSavedSettings, "CameraOpacity");
+	static LLCachedControl<F32> active_floater_transparency(gSavedSettings, "ActiveFloaterTransparency");
+	return llmin(camera_opacity(), active_floater_transparency());
+
+}
+
 void LLFloaterCamera::fillFlatlistFromPanel (LLFlatListView* list, LLPanel* panel)
 {
 	// copying child list and then iterating over a copy, because list itself
@@ -444,13 +457,6 @@ void LLFloaterCamera::switchMode(ECameraControlMode mode)
 
 	switch (mode)
 	{
-	case CAMERA_CTRL_MODE_MODES:
-		if(sFreeCamera)
-		{
-			switchMode(CAMERA_CTRL_MODE_FREE_CAMERA);
-		}
-		break;
-
 	case CAMERA_CTRL_MODE_PAN:
 		sFreeCamera = false;
 		clear_camera_tool();
@@ -474,36 +480,8 @@ void LLFloaterCamera::switchMode(ECameraControlMode mode)
 	}
 }
 
-
-void LLFloaterCamera::onClickBtn(ECameraControlMode mode)
-{
-	// check for a click on active button
-	if (mCurrMode == mode) mMode2Button[mode]->setToggleState(TRUE);
-	
-	switchMode(mode);
-
-}
-
-void LLFloaterCamera::assignButton2Mode(ECameraControlMode mode, const std::string& button_name)
-{
-	LLButton* button = getChild<LLButton>(button_name);
-	
-	button->setClickedCallback(boost::bind(&LLFloaterCamera::onClickBtn, this, mode));
-	mMode2Button[mode] = button;
-}
-
 void LLFloaterCamera::updateState()
 {
-	getChildView(ZOOM)->setVisible(CAMERA_CTRL_MODE_PAN == mCurrMode);
-	
-	bool show_presets = (CAMERA_CTRL_MODE_PRESETS == mCurrMode) || (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode
-																	&& CAMERA_CTRL_MODE_PRESETS == mPrevMode);
-	getChildView(PRESETS)->setVisible(show_presets);
-	
-	bool show_camera_modes = CAMERA_CTRL_MODE_MODES == mCurrMode || (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode
-																	&& CAMERA_CTRL_MODE_MODES == mPrevMode);
-	getChildView("camera_modes_list")->setVisible( show_camera_modes);
-
 	updateItemsSelection();
 
 	if (CAMERA_CTRL_MODE_FREE_CAMERA == mCurrMode)
@@ -521,13 +499,13 @@ void LLFloaterCamera::updateState()
 
 void LLFloaterCamera::updateItemsSelection()
 {
-	ECameraPreset preset = (ECameraPreset) gSavedSettings.getU32("CameraPreset");
+	ECameraPreset preset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType");
 	LLSD argument;
-	argument["selected"] = preset == CAMERA_PRESET_REAR_VIEW;
+	argument["selected"] = (preset == CAMERA_PRESET_REAR_VIEW) && !sFreeCamera;
 	getChild<LLPanelCameraItem>("rear_view")->setValue(argument);
-	argument["selected"] = preset == CAMERA_PRESET_GROUP_VIEW;
+	argument["selected"] = (preset == CAMERA_PRESET_GROUP_VIEW) && !sFreeCamera;
 	getChild<LLPanelCameraItem>("group_view")->setValue(argument);
-	argument["selected"] = preset == CAMERA_PRESET_FRONT_VIEW;
+	argument["selected"] = (preset == CAMERA_PRESET_FRONT_VIEW) && !sFreeCamera;
 	getChild<LLPanelCameraItem>("front_view")->setValue(argument);
 	argument["selected"] = gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK;
 	getChild<LLPanelCameraItem>("mouselook_view")->setValue(argument);
@@ -547,19 +525,19 @@ void LLFloaterCamera::onClickCameraItem(const LLSD& param)
 	{
 		LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance();
 		if (camera_floater)
-		camera_floater->switchMode(CAMERA_CTRL_MODE_FREE_CAMERA);
+		{
+			camera_floater->switchMode(CAMERA_CTRL_MODE_FREE_CAMERA);
+			camera_floater->updateItemsSelection();
+			camera_floater->fromFreeToPresets();
+		}
 	}
 	else
 	{
+		LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance();
+		if (camera_floater)
+			camera_floater->switchMode(CAMERA_CTRL_MODE_PAN);
 		switchToPreset(name);
 	}
-
-	LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance();
-	if (camera_floater)
-	{
-		camera_floater->updateItemsSelection();
-		camera_floater->fromFreeToPresets();
-	}
 }
 
 /*static*/
@@ -567,18 +545,49 @@ void LLFloaterCamera::switchToPreset(const std::string& name)
 {
 	sFreeCamera = false;
 	clear_camera_tool();
-	if ("rear_view" == name)
+	if (PRESETS_REAR_VIEW == name)
 	{
 		gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
 	}
-	else if ("group_view" == name)
+	else if (PRESETS_SIDE_VIEW == name)
 	{
 		gAgentCamera.switchCameraPreset(CAMERA_PRESET_GROUP_VIEW);
 	}
-	else if ("front_view" == name)
+	else if (PRESETS_FRONT_VIEW == name)
 	{
 		gAgentCamera.switchCameraPreset(CAMERA_PRESET_FRONT_VIEW);
 	}
+	else
+	{
+		gAgentCamera.switchCameraPreset(CAMERA_PRESET_CUSTOM);
+	}
+	
+	if (gSavedSettings.getString("PresetCameraActive") != name)
+	{
+		LLPresetsManager::getInstance()->loadPreset(PRESETS_CAMERA, name);
+	}
+
+	if (isAgentAvatarValid() && gAgentAvatarp->getParent())
+	{
+		LLQuaternion sit_rot(gSavedSettings.getLLSD("AvatarSitRotation"));
+		if (sit_rot != LLQuaternion())
+		{
+			gAgent.rotate(~gAgent.getFrameAgent().getQuaternion());
+			gAgent.rotate(sit_rot);
+		}
+		else
+		{
+			gAgentCamera.rotateToInitSitRot();
+		}
+	}
+	gAgentCamera.resetCameraZoomFraction();
+
+	LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance();
+	if (camera_floater)
+	{
+		camera_floater->updateItemsSelection();
+		camera_floater->fromFreeToPresets();
+	}
 }
 
 void LLFloaterCamera::fromFreeToPresets()
@@ -588,3 +597,41 @@ void LLFloaterCamera::fromFreeToPresets()
 		switchMode(CAMERA_CTRL_MODE_PRESETS);
 	}
 }
+
+void LLFloaterCamera::populatePresetCombo()
+{
+	LLPresetsManager::getInstance()->setPresetNamesInComboBox(PRESETS_CAMERA, mPresetCombo, EDefaultOptions::DEFAULT_HIDE);
+	std::string active_preset_name = gSavedSettings.getString("PresetCameraActive");
+	if (active_preset_name.empty())
+	{
+		gSavedSettings.setU32("CameraPresetType", CAMERA_PRESET_CUSTOM);
+		updateItemsSelection();
+		mPresetCombo->setLabel(getString("inactive_combo_text"));
+	}
+	else if ((ECameraPreset)gSavedSettings.getU32("CameraPresetType") == CAMERA_PRESET_CUSTOM)
+	{
+		mPresetCombo->selectByValue(active_preset_name);
+	}
+	else
+	{
+		mPresetCombo->setLabel(getString("inactive_combo_text"));
+	}
+	updateItemsSelection();
+}
+
+void LLFloaterCamera::onSavePreset()
+{
+	LLFloaterReg::hideInstance("delete_pref_preset", PRESETS_CAMERA);
+	LLFloaterReg::hideInstance("load_pref_preset", PRESETS_CAMERA);
+	
+	LLFloaterReg::showInstance("save_camera_preset");
+}
+
+void LLFloaterCamera::onCustomPresetSelected()
+{
+	std::string selected_preset = mPresetCombo->getSelectedItemLabel();
+	if (getString("inactive_combo_text") != selected_preset)
+	{
+		switchToPreset(selected_preset);
+	}
+}
diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h
index 4d6d03f22d9078e150720bf44b6ee3fdba7753c1..9440f50c3fd15b6d8787702e6273d0b102f670b7 100644
--- a/indra/newview/llfloatercamera.h
+++ b/indra/newview/llfloatercamera.h
@@ -36,10 +36,10 @@ class LLJoystickCameraRotate;
 class LLJoystickCameraTrack;
 class LLFloaterReg;
 class LLPanelCameraZoom;
+class LLComboBox;
 
 enum ECameraControlMode
 {
-	CAMERA_CTRL_MODE_MODES,
 	CAMERA_CTRL_MODE_PAN,
 	CAMERA_CTRL_MODE_FREE_CAMERA,
 	CAMERA_CTRL_MODE_PRESETS
@@ -50,7 +50,6 @@ class LLFloaterCamera : public LLFloater
 	friend class LLFloaterReg;
 	
 public:
-
 	/* whether in free camera mode */
 	static bool inFreeCameraMode();
 	/* callback for camera items selection changing */
@@ -77,6 +76,11 @@ class LLFloaterCamera : public LLFloater
 	virtual void onOpen(const LLSD& key);
 	virtual void onClose(bool app_quitting);
 
+	void onSavePreset();
+	void onCustomPresetSelected();
+
+	void populatePresetCombo();
+
 	LLJoystickCameraRotate* mRotate;
 	LLPanelCameraZoom*	mZoom;
 	LLJoystickCameraTrack*	mTrack;
@@ -91,6 +95,10 @@ class LLFloaterCamera : public LLFloater
 
 	/*virtual*/ BOOL postBuild();
 
+	F32 getCurrentTransparency();
+
+	void onViewButtonClick(const LLSD& user_data);
+
 	ECameraControlMode determineMode();
 
 	/* resets to the previous mode */
@@ -108,9 +116,6 @@ class LLFloaterCamera : public LLFloater
 	/* update camera modes items selection and camera preset items selection according to the currently selected preset */
 	void updateItemsSelection();
 
-	void onClickBtn(ECameraControlMode mode);
-	void assignButton2Mode(ECameraControlMode mode, const std::string& button_name);
-	
 	// fills flatlist with items from given panel
 	void fillFlatlistFromPanel (LLFlatListView* list, LLPanel* panel);
 
@@ -124,6 +129,8 @@ class LLFloaterCamera : public LLFloater
 	ECameraControlMode mPrevMode;
 	ECameraControlMode mCurrMode;
 	std::map<ECameraControlMode, LLButton*> mMode2Button;
+
+	LLComboBox* mPresetCombo;
 };
 
 /**
diff --git a/indra/newview/llfloatercamerapresets.cpp b/indra/newview/llfloatercamerapresets.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..300c945a859ca845696350d935b1236a0b5085c0
--- /dev/null
+++ b/indra/newview/llfloatercamerapresets.cpp
@@ -0,0 +1,145 @@
+/** 
+* @file llfloatercamerapresets.cpp
+*
+* $LicenseInfo:firstyear=2019&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2019, 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 "llfloatercamerapresets.h"
+#include "llfloaterreg.h"
+#include "llnotificationsutil.h"
+#include "llpresetsmanager.h"
+#include "llviewercontrol.h"
+
+LLFloaterCameraPresets::LLFloaterCameraPresets(const LLSD& key)
+:	LLFloater(key)
+{}
+
+LLFloaterCameraPresets::~LLFloaterCameraPresets()
+{}
+
+BOOL LLFloaterCameraPresets::postBuild()
+{
+    mPresetList = getChild<LLFlatListView>("preset_list");
+
+    LLPresetsManager::getInstance()->setPresetListChangeCameraCallback(boost::bind(&LLFloaterCameraPresets::populateList, this));
+
+    return TRUE;
+}
+void LLFloaterCameraPresets::onOpen(const LLSD& key)
+{
+    populateList();
+}
+
+void LLFloaterCameraPresets::populateList()
+{
+    mPresetList->clear();
+
+    LLPresetsManager* presetsMgr = LLPresetsManager::getInstance();
+    std::list<std::string> preset_names;
+
+	presetsMgr->loadPresetNamesFromDir(PRESETS_CAMERA, preset_names, DEFAULT_BOTTOM);
+
+    for (std::list<std::string>::const_iterator it = preset_names.begin(); it != preset_names.end(); ++it)
+    {
+        const std::string& name = *it;
+        bool is_default = presetsMgr->isDefaultCameraPreset(name);
+        LLCameraPresetFlatItem* item = new LLCameraPresetFlatItem(name, is_default);
+        item->postBuild();
+        mPresetList->addItem(item);
+    }
+}
+
+LLCameraPresetFlatItem::LLCameraPresetFlatItem(const std::string &preset_name, bool is_default)
+    : LLPanel(),
+    mPresetName(preset_name),
+    mIsDefaultPrest(is_default)
+{
+    mCommitCallbackRegistrar.add("CameraPresets.Delete", boost::bind(&LLCameraPresetFlatItem::onDeleteBtnClick, this));
+    mCommitCallbackRegistrar.add("CameraPresets.Reset", boost::bind(&LLCameraPresetFlatItem::onResetBtnClick, this));
+    buildFromFile("panel_camera_preset_item.xml");
+}
+
+LLCameraPresetFlatItem::~LLCameraPresetFlatItem()
+{
+}
+
+BOOL LLCameraPresetFlatItem::postBuild()
+{
+    mDeleteBtn = getChild<LLButton>("delete_btn");
+    mDeleteBtn->setVisible(false);
+
+    mResetBtn = getChild<LLButton>("reset_btn");
+    mResetBtn->setVisible(false);
+
+    LLStyle::Params style;
+    LLTextBox* name_text = getChild<LLTextBox>("preset_name");
+    LLFontDescriptor new_desc(name_text->getFont()->getFontDesc());
+    new_desc.setStyle(mIsDefaultPrest ? LLFontGL::ITALIC : LLFontGL::NORMAL);
+    LLFontGL* new_font = LLFontGL::getFont(new_desc);
+    style.font = new_font;
+    name_text->setText(mPresetName, style);
+
+    return true;
+}
+
+void LLCameraPresetFlatItem::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+    mDeleteBtn->setVisible(!mIsDefaultPrest);
+    mResetBtn->setVisible(mIsDefaultPrest);
+    getChildView("hovered_icon")->setVisible(true);
+    LLPanel::onMouseEnter(x, y, mask);
+}
+
+void LLCameraPresetFlatItem::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+    mDeleteBtn->setVisible(false);
+    mResetBtn->setVisible(false);
+    getChildView("hovered_icon")->setVisible(false);
+    LLPanel::onMouseLeave(x, y, mask);
+}
+
+void LLCameraPresetFlatItem::setValue(const LLSD& value)
+{
+    if (!value.isMap()) return;;
+    if (!value.has("selected")) return;
+    getChildView("selected_icon")->setVisible(value["selected"]);
+}
+
+void LLCameraPresetFlatItem::onDeleteBtnClick()
+{
+    if (!LLPresetsManager::getInstance()->deletePreset(PRESETS_CAMERA, mPresetName))
+    {
+        LLSD args;
+        args["NAME"] = mPresetName;
+        LLNotificationsUtil::add("PresetNotDeleted", args);
+    }
+	else if (gSavedSettings.getString("PresetCameraActive") == mPresetName)
+    {
+        gSavedSettings.setString("PresetCameraActive", "");
+    }
+}
+
+void LLCameraPresetFlatItem::onResetBtnClick()
+{
+    LLPresetsManager::getInstance()->resetCameraPreset(mPresetName);
+}
diff --git a/indra/newview/llfloatercamerapresets.h b/indra/newview/llfloatercamerapresets.h
new file mode 100644
index 0000000000000000000000000000000000000000..66430fa399441f67a52aae5944e0ed915b5d8689
--- /dev/null
+++ b/indra/newview/llfloatercamerapresets.h
@@ -0,0 +1,73 @@
+/** 
+* @file llfloatercamerapresets.h
+*
+* $LicenseInfo:firstyear=2019&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2019, 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 LLFLOATERCAMERAPRESETS_H
+#define LLFLOATERCAMERAPRESETS_H
+
+#include "llfloater.h"
+#include "llflatlistview.h"
+
+class LLFloaterReg;
+
+class LLFloaterCameraPresets : public LLFloater
+{
+    friend class LLFloaterReg;
+
+    virtual BOOL postBuild();
+    virtual void onOpen(const LLSD& key);
+
+    void populateList();
+
+private:
+    LLFloaterCameraPresets(const LLSD& key);
+    ~LLFloaterCameraPresets();
+
+    LLFlatListView* mPresetList;
+};
+
+class LLCameraPresetFlatItem : public LLPanel
+{
+public:
+    LLCameraPresetFlatItem(const std::string &preset_name, bool is_default);
+    virtual ~LLCameraPresetFlatItem();
+
+    void setValue(const LLSD& value);
+
+    virtual BOOL postBuild();
+    virtual void onMouseEnter(S32 x, S32 y, MASK mask);
+    virtual void onMouseLeave(S32 x, S32 y, MASK mask);
+
+private:
+    void onDeleteBtnClick();
+    void onResetBtnClick();
+
+    LLButton* mDeleteBtn;
+    LLButton* mResetBtn;
+
+    std::string mPresetName;
+    bool mIsDefaultPrest;
+
+};
+
+#endif
diff --git a/indra/newview/llfloaterdeleteprefpreset.cpp b/indra/newview/llfloaterdeleteprefpreset.cpp
index 7dedbbf98430169016ec275228f84c7bcdfae203..0765756b433b86cd260c4165f4cf99ee519779d6 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()
@@ -80,6 +82,13 @@ void LLFloaterDeletePrefPreset::onBtnDelete()
 		args["NAME"] = name;
 		LLNotificationsUtil::add("PresetNotDeleted", args);
 	}
+	else if (mSubdirectory == PRESETS_CAMERA)
+	{
+		if (gSavedSettings.getString("PresetCameraActive") == name)
+		{
+			gSavedSettings.setString("PresetCameraActive", "");
+		}
+	}
 
 	closeFloater();
 }
@@ -87,12 +96,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/llfloaterloadprefpreset.cpp b/indra/newview/llfloaterloadprefpreset.cpp
index 403db35cc020c57c93c0df43a12fa5c6c15753f1..fa17a9d40e3d08e0e37b99b1044deaa6328d295c 100644
--- a/indra/newview/llfloaterloadprefpreset.cpp
+++ b/indra/newview/llfloaterloadprefpreset.cpp
@@ -42,7 +42,8 @@ LLFloaterLoadPrefPreset::LLFloaterLoadPrefPreset(const LLSD &key)
 
 // virtual
 BOOL LLFloaterLoadPrefPreset::postBuild()
-{	LLFloaterPreference* preferences = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences");
+{
+	LLFloaterPreference* preferences = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences");
 	if (preferences)
 	{
 		preferences->addDependentFloater(this);
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 093753c9679faea06d43622d97b5ee83315acd37..951d11bbe5461fdeaded6139eedb7566fc37515d 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -725,7 +725,7 @@ void LLFloaterPreference::cancel()
 	// hide spellchecker settings folder
 	LLFloaterReg::hideInstance("prefs_spellchecker");
 
-	// hide advancede floater
+	// hide advanced graphics floater
 	LLFloaterReg::hideInstance("prefs_graphics_advanced");
 	
 	// reverts any changes to current skin
@@ -844,7 +844,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);
 
@@ -853,12 +854,15 @@ void LLFloaterPreference::onOpen(const LLSD& key)
 	LLButton* delete_btn = findChild<LLButton>("PrefDeleteButton");
 	LLButton* exceptions_btn = findChild<LLButton>("RenderExceptionsButton");
 
-	load_btn->setEnabled(started);
-	save_btn->setEnabled(started);
-	delete_btn->setEnabled(started);
-	exceptions_btn->setEnabled(started);
+	if (load_btn && save_btn && delete_btn && exceptions_btn)
+	{
+		load_btn->setEnabled(started);
+		save_btn->setEnabled(started);
+		delete_btn->setEnabled(started);
+		exceptions_btn->setEnabled(started);
+	}
 
-	collectSearchableItems();
+    collectSearchableItems();
 	if (!mFilterEdit->getText().empty())
 	{
 		mFilterEdit->setText(LLStringExplicit(""));
@@ -2633,20 +2637,17 @@ void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl)
 
 void LLPanelPreference::deletePreset(const LLSD& user_data)
 {
-	std::string subdirectory = user_data.asString();
-	LLFloaterReg::showInstance("delete_pref_preset", subdirectory);
+	LLFloaterReg::showInstance("delete_pref_preset", user_data.asString());
 }
 
 void LLPanelPreference::savePreset(const LLSD& user_data)
 {
-	std::string subdirectory = user_data.asString();
-	LLFloaterReg::showInstance("save_pref_preset", subdirectory);
+	LLFloaterReg::showInstance("save_pref_preset", user_data.asString());
 }
 
 void LLPanelPreference::loadPreset(const LLSD& user_data)
 {
-	std::string subdirectory = user_data.asString();
-	LLFloaterReg::showInstance("load_pref_preset", subdirectory);
+	LLFloaterReg::showInstance("load_pref_preset", user_data.asString());
 }
 
 void LLPanelPreference::setHardwareDefaults()
@@ -2704,7 +2705,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();
 }
@@ -2725,11 +2726,6 @@ void LLPanelPreferenceGraphics::onPresetsListChange()
 	{
 		instance->saveSettings(); //make cancel work correctly after changing the preset
 	}
-	else
-	{
-		std::string dummy;
-		instance->saveGraphicsPreset(dummy);
-	}
 }
 
 void LLPanelPreferenceGraphics::setPresetText()
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index a0f43bd8848e4560e3605d3c014d499e90e6ff37..526214a617b2af0fa67e434c723aa90af28b8ec9 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -191,6 +191,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:
@@ -214,6 +215,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver,
 	std::string mDirectoryVisibility;
 	
 	LLAvatarData mAvatarProperties;
+	std::string mSavedCameraPreset;
 	std::string mSavedGraphicsPreset;
 	LOG_CLASS(LLFloaterPreference);
 
@@ -288,7 +290,6 @@ class LLPanelPreferenceGraphics : public LLPanelPreference
 	bool hasDirtyChilds();
 
 private:
-
 	void onPresetsListChange();
 	LOG_CLASS(LLPanelPreferenceGraphics);
 };
diff --git a/indra/newview/llfloaterpreferenceviewadvanced.cpp b/indra/newview/llfloaterpreferenceviewadvanced.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f8db738923359072443744297795191971ee1e2b
--- /dev/null
+++ b/indra/newview/llfloaterpreferenceviewadvanced.cpp
@@ -0,0 +1,82 @@
+/** 
+ * @file llfloaterpreferenceviewadvanced.cpp
+ * @brief floater for adjusting camera position
+ *
+ * $LicenseInfo:firstyear=2018&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2018, 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 "llagentcamera.h"
+#include "llfloaterpreferenceviewadvanced.h"
+#include "llfloater.h"
+#include "llfloaterreg.h"
+#include "lluictrlfactory.h"
+#include "llspinctrl.h"
+#include "llviewercontrol.h"
+
+
+LLFloaterPreferenceViewAdvanced::LLFloaterPreferenceViewAdvanced(const LLSD& key) 
+:	LLFloater(key)
+{
+	mCommitCallbackRegistrar.add("CommitSettings",	boost::bind(&LLFloaterPreferenceViewAdvanced::onCommitSettings, this));
+}
+
+LLFloaterPreferenceViewAdvanced::~LLFloaterPreferenceViewAdvanced()
+{}
+
+void LLFloaterPreferenceViewAdvanced::updateCameraControl(const LLVector3& vector)
+{
+	getChild<LLSpinCtrl>("camera_x")->setValue(vector[VX]);
+	getChild<LLSpinCtrl>("camera_y")->setValue(vector[VY]);
+	getChild<LLSpinCtrl>("camera_z")->setValue(vector[VZ]);
+}
+
+void LLFloaterPreferenceViewAdvanced::updateFocusControl(const LLVector3d& vector3d)
+{
+	getChild<LLSpinCtrl>("focus_x")->setValue(vector3d[VX]);
+	getChild<LLSpinCtrl>("focus_y")->setValue(vector3d[VY]);
+	getChild<LLSpinCtrl>("focus_z")->setValue(vector3d[VZ]);
+}
+
+ void LLFloaterPreferenceViewAdvanced::draw()
+{
+	updateCameraControl(gAgentCamera.getCameraOffsetInitial());
+	updateFocusControl(gAgentCamera.getFocusOffsetInitial());
+
+	LLFloater::draw();
+}
+
+void LLFloaterPreferenceViewAdvanced::onCommitSettings()
+{
+	LLVector3 vector;
+	LLVector3d vector3d;
+
+	vector.mV[VX] = (F32)getChild<LLUICtrl>("camera_x")->getValue().asReal();
+	vector.mV[VY] = (F32)getChild<LLUICtrl>("camera_y")->getValue().asReal();
+	vector.mV[VZ] = (F32)getChild<LLUICtrl>("camera_z")->getValue().asReal();
+	gSavedSettings.setVector3("CameraOffsetRearView", vector);
+
+	vector3d.mdV[VX] = (F32)getChild<LLUICtrl>("focus_x")->getValue().asReal();
+	vector3d.mdV[VY] = (F32)getChild<LLUICtrl>("focus_y")->getValue().asReal();
+	vector3d.mdV[VZ] = (F32)getChild<LLUICtrl>("focus_z")->getValue().asReal();
+	gSavedSettings.setVector3d("FocusOffsetRearView", vector3d);
+}
diff --git a/indra/newview/llfloaterpreferenceviewadvanced.h b/indra/newview/llfloaterpreferenceviewadvanced.h
new file mode 100644
index 0000000000000000000000000000000000000000..4619fdaab16b9f79aaea2071b04c5c5252556adb
--- /dev/null
+++ b/indra/newview/llfloaterpreferenceviewadvanced.h
@@ -0,0 +1,51 @@
+/** 
+ * @file llfloaterpreferenceviewadvanced.h
+ * @brief floater for adjusting camera position
+ *
+ * $LicenseInfo:firstyear=2018&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2018, 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 LLFLOATERPREFERENCEVIEWADVANCED_H
+#define LLFLOATERPREFERENCEVIEWADVANCED_H
+
+#include "llcontrol.h"
+#include "llfloater.h"
+
+class LLFloaterPreferenceViewAdvanced
+:	public LLFloater
+{
+	friend class LLFloaterReg;
+
+public:
+	LLFloaterPreferenceViewAdvanced(const LLSD& key);
+	virtual void draw();
+
+	void onCommitSettings();
+	void updateCameraControl(const LLVector3& vector);
+	void updateFocusControl(const LLVector3d& vector3d);
+
+private:
+	virtual ~LLFloaterPreferenceViewAdvanced();
+};
+
+#endif //LLFLOATERPREFERENCEVIEWADVANCED_H
+
diff --git a/indra/newview/llfloatersavecamerapreset.cpp b/indra/newview/llfloatersavecamerapreset.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..11809f9c824369c5793b7027bede4b48f441a1d4
--- /dev/null
+++ b/indra/newview/llfloatersavecamerapreset.cpp
@@ -0,0 +1,172 @@
+/** 
+ * @file llfloatersavecamerapreset.cpp
+ * @brief Floater to save a camera preset
+ *
+ * $LicenseInfo:firstyear=2020&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2020, 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 "llfloatersavecamerapreset.h"
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llbutton.h"
+#include "llcombobox.h"
+#include "llfloaterpreference.h"
+#include "llfloaterreg.h"
+#include "lllineeditor.h"
+#include "llnotificationsutil.h"
+#include "llpresetsmanager.h"
+#include "llradiogroup.h"
+#include "lltrans.h"
+#include "llvoavatarself.h"
+
+LLFloaterSaveCameraPreset::LLFloaterSaveCameraPreset(const LLSD &key)
+	: LLModalDialog(key)
+{
+}
+
+// virtual
+BOOL LLFloaterSaveCameraPreset::postBuild()
+{
+	mPresetCombo = getChild<LLComboBox>("preset_combo");
+
+	mNameEditor = getChild<LLLineEditor>("preset_txt_editor");
+	mNameEditor->setKeystrokeCallback(boost::bind(&LLFloaterSaveCameraPreset::onPresetNameEdited, this), NULL);
+
+	mSaveButton = getChild<LLButton>("save");
+	mSaveButton->setCommitCallback(boost::bind(&LLFloaterSaveCameraPreset::onBtnSave, this));
+	
+	mSaveRadioGroup = getChild<LLRadioGroup>("radio_save_preset");
+	mSaveRadioGroup->setCommitCallback(boost::bind(&LLFloaterSaveCameraPreset::onSwitchSaveReplace, this));
+	
+	getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterSaveCameraPreset::onBtnCancel, this));
+
+	LLPresetsManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterSaveCameraPreset::onPresetsListChange, this));
+
+	return TRUE;
+}
+
+void LLFloaterSaveCameraPreset::onPresetNameEdited()
+{
+	if (mSaveRadioGroup->getSelectedIndex() == 0)
+	{
+		// Disable saving a preset having empty name.
+		std::string name = mNameEditor->getValue();
+		mSaveButton->setEnabled(!name.empty());
+	}
+}
+
+void LLFloaterSaveCameraPreset::onOpen(const LLSD& key)
+{
+	LLModalDialog::onOpen(key);
+	S32 index = 0;
+	if (key.has("index"))
+	{
+		index = key["index"].asInteger();
+	}
+
+	LLPresetsManager::getInstance()->setPresetNamesInComboBox(PRESETS_CAMERA, mPresetCombo, DEFAULT_BOTTOM);
+
+	mSaveRadioGroup->setSelectedIndex(index);
+	onPresetNameEdited();
+	onSwitchSaveReplace();
+}
+
+void LLFloaterSaveCameraPreset::onBtnSave()
+{
+	bool is_saving_new = mSaveRadioGroup->getSelectedIndex() == 0;
+	std::string name = is_saving_new ? mNameEditor->getText() : mPresetCombo->getSimple();
+
+	if ((name == LLTrans::getString(PRESETS_DEFAULT)) || (name == PRESETS_DEFAULT))
+	{
+		LLNotificationsUtil::add("DefaultPresetNotSaved");
+	}
+	else 
+	{
+		if (isAgentAvatarValid() && gAgentAvatarp->getParent())
+		{
+			gSavedSettings.setLLSD("AvatarSitRotation", gAgent.getFrameAgent().getQuaternion().getValue());
+		}
+		if (gAgentCamera.isJoystickCameraUsed())
+		{
+			gSavedSettings.setVector3("CameraOffsetRearView", gAgentCamera.getCurrentCameraOffset());
+			gSavedSettings.setVector3d("FocusOffsetRearView", gAgentCamera.getCurrentFocusOffset());
+			gAgentCamera.resetCameraZoomFraction();
+			gAgentCamera.setFocusOnAvatar(TRUE, TRUE, FALSE);
+		}
+		else
+		{
+			LLVector3 camera_offset = gSavedSettings.getVector3("CameraOffsetRearView") * gAgentCamera.getCurrentCameraZoomFraction();
+			gSavedSettings.setVector3("CameraOffsetRearView", camera_offset);
+			gAgentCamera.resetCameraZoomFraction();
+		}
+		if (is_saving_new)
+		{
+			std::list<std::string> preset_names;
+			LLPresetsManager::getInstance()->loadPresetNamesFromDir(PRESETS_CAMERA, preset_names, DEFAULT_HIDE);
+			if (std::find(preset_names.begin(), preset_names.end(), name) != preset_names.end())
+			{
+				LLSD args;
+				args["NAME"] = name;
+				LLNotificationsUtil::add("PresetAlreadyExists", args);
+				return;
+			}
+		}
+		if (!LLPresetsManager::getInstance()->savePreset(PRESETS_CAMERA, name))
+		{
+			LLSD args;
+			args["NAME"] = name;
+			LLNotificationsUtil::add("PresetNotSaved", args);
+		}
+	}
+
+	closeFloater();
+}
+
+void LLFloaterSaveCameraPreset::onPresetsListChange()
+{
+	LLPresetsManager::getInstance()->setPresetNamesInComboBox(PRESETS_CAMERA, mPresetCombo, DEFAULT_BOTTOM);
+}
+
+void LLFloaterSaveCameraPreset::onBtnCancel()
+{
+	closeFloater();
+}
+
+void LLFloaterSaveCameraPreset::onSwitchSaveReplace()
+{
+	bool is_saving_new = mSaveRadioGroup->getSelectedIndex() == 0;
+	std::string label = is_saving_new ? getString("btn_label_save") : getString("btn_label_replace");
+	mSaveButton->setLabel(label);
+	mNameEditor->setEnabled(is_saving_new);
+	mPresetCombo->setEnabled(!is_saving_new);
+	if (is_saving_new)
+	{
+		onPresetNameEdited();
+	}
+	else
+	{
+		mSaveButton->setEnabled(true);
+	}
+}
diff --git a/indra/newview/llfloatersavecamerapreset.h b/indra/newview/llfloatersavecamerapreset.h
new file mode 100644
index 0000000000000000000000000000000000000000..282f213438c7e0b91940941bafa1015d07864a02
--- /dev/null
+++ b/indra/newview/llfloatersavecamerapreset.h
@@ -0,0 +1,60 @@
+/** 
+ * @file llfloatersavecamerapreset.h
+ * @brief Floater to save a camera preset
+
+ *
+ * $LicenseInfo:firstyear=2020&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2020, 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_LLFLOATERSAVECAMERAPRESET_H
+#define LL_LLFLOATERSAVECAMERAPRESET_H
+
+#include "llmodaldialog.h"
+
+class LLComboBox;
+class LLRadioGroup;
+class LLLineEditor;
+
+class LLFloaterSaveCameraPreset : public LLModalDialog
+{
+
+public:
+	LLFloaterSaveCameraPreset(const LLSD &key);
+
+	/*virtual*/	BOOL	postBuild();
+	/*virtual*/ void	onOpen(const LLSD& key);
+
+	void onBtnSave();
+	void onBtnCancel();
+	void onSwitchSaveReplace();
+
+private:
+	LLRadioGroup*	mSaveRadioGroup;
+	LLLineEditor*	mNameEditor;
+	LLComboBox*		mPresetCombo;
+	LLButton*		mSaveButton;
+
+	void onPresetsListChange();
+	void onPresetNameEdited();
+};
+
+#endif // LL_LLFLOATERSAVECAMERAPRESET_H
diff --git a/indra/newview/llfloatersaveprefpreset.cpp b/indra/newview/llfloatersaveprefpreset.cpp
index 684778c93ac8c1f31389eeaf9478aea19e1c2fef..5f3cf9d95bc195e53c0a066a59a20e9657a3d281 100644
--- a/indra/newview/llfloatersaveprefpreset.cpp
+++ b/indra/newview/llfloatersaveprefpreset.cpp
@@ -1,6 +1,6 @@
 /** 
  * @file llfloatersaveprefpreset.cpp
- * @brief Floater to save a graphics / camera preset
+ * @brief Floater to save a graphics preset
  *
  * $LicenseInfo:firstyear=2014&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -37,24 +37,27 @@
 #include "lltrans.h"
 
 LLFloaterSavePrefPreset::LLFloaterSavePrefPreset(const LLSD &key)
-:	LLFloater(key)
+	: LLFloater(key)
 {
 }
 
 // virtual
 BOOL LLFloaterSavePrefPreset::postBuild()
-{	LLFloaterPreference* preferences = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences");
+{
+	LLFloaterPreference* preferences = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences");
 	if (preferences)
 	{
 		preferences->addDependentFloater(this);
 	}
+	
 	getChild<LLComboBox>("preset_combo")->setTextEntryCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetNameEdited, this));
 	getChild<LLComboBox>("preset_combo")->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetNameEdited, this));
 	getChild<LLButton>("save")->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onBtnSave, this));
+
 	getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onBtnCancel, this));
 
 	LLPresetsManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetsListChange, this));
-
+	
 	mSaveButton = getChild<LLButton>("save");
 	mPresetCombo = getChild<LLComboBox>("preset_combo");
 
@@ -73,10 +76,6 @@ void LLFloaterSavePrefPreset::onOpen(const LLSD& key)
 {
 	mSubdirectory = key.asString();
 
-	std::string floater_title = getString(std::string("title_") + mSubdirectory);
-
-	setTitle(floater_title);
-
 	EDefaultOptions option = DEFAULT_HIDE;
 	LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, mPresetCombo, option);
 
diff --git a/indra/newview/llfloatersaveprefpreset.h b/indra/newview/llfloatersaveprefpreset.h
index 09a87b8c6296b7cb39fdec8b4953736eb19e03db..ae58180e7f46dbc1cc0a8c8f93f45b39ca911120 100644
--- a/indra/newview/llfloatersaveprefpreset.h
+++ b/indra/newview/llfloatersaveprefpreset.h
@@ -1,6 +1,6 @@
 /** 
  * @file llfloatersaveprefpreset.h
- * @brief Floater to save a graphics / camera preset
+ * @brief Floater to save a graphics preset
 
  *
  * $LicenseInfo:firstyear=2014&license=viewerlgpl$
@@ -45,6 +45,7 @@ class LLFloaterSavePrefPreset : public LLFloater
 	void onBtnCancel();
 
 private:
+
 	LLComboBox*		mPresetCombo;
 	LLButton*		mSaveButton;
 
diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp
index fb202b4c406189156a8a0a86de2316aec649156e..186994c8571c118669aef4a2642e6cf55f4fd526 100644
--- a/indra/newview/llfloatersettingsdebug.cpp
+++ b/indra/newview/llfloatersettingsdebug.cpp
@@ -111,6 +111,7 @@ void LLFloaterSettingsDebug::onCommitSettings()
 
 	LLVector3 vector;
 	LLVector3d vectord;
+	LLQuaternion quat;
 	LLRect rect;
 	LLColor4 col4;
 	LLColor3 col3;
@@ -146,6 +147,13 @@ void LLFloaterSettingsDebug::onCommitSettings()
 		vectord.mdV[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal();
 		controlp->set(vectord.getValue());
 		break;
+	  case TYPE_QUAT:
+		quat.mQ[VX] = getChild<LLUICtrl>("val_spinner_1")->getValue().asReal();
+		quat.mQ[VY] = getChild<LLUICtrl>("val_spinner_2")->getValue().asReal();
+		quat.mQ[VZ] = getChild<LLUICtrl>("val_spinner_3")->getValue().asReal();
+		quat.mQ[VS] = getChild<LLUICtrl>("val_spinner_4")->getValue().asReal();;
+		controlp->set(quat.getValue());
+		break;
 	  case TYPE_RECT:
 		rect.mLeft = getChild<LLUICtrl>("val_spinner_1")->getValue().asInteger();
 		rect.mRight = getChild<LLUICtrl>("val_spinner_2")->getValue().asInteger();
@@ -351,6 +359,40 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)
 			}
 			break;
 		  }
+		  case TYPE_QUAT:
+		  {
+			  LLQuaternion q;
+			  q.setValue(sd);
+			  spinner1->setVisible(TRUE);
+			  spinner1->setLabel(std::string("X"));
+			  spinner2->setVisible(TRUE);
+			  spinner2->setLabel(std::string("Y"));
+			  spinner3->setVisible(TRUE);
+			  spinner3->setLabel(std::string("Z"));
+			  spinner4->setVisible(TRUE);
+			  spinner4->setLabel(std::string("S"));
+			  if (!spinner1->hasFocus())
+			  {
+				  spinner1->setPrecision(4);
+				  spinner1->setValue(q.mQ[VX]);
+			  }
+			  if (!spinner2->hasFocus())
+			  {
+				  spinner2->setPrecision(4);
+				  spinner2->setValue(q.mQ[VY]);
+			  }
+			  if (!spinner3->hasFocus())
+			  {
+				  spinner3->setPrecision(4);
+				  spinner3->setValue(q.mQ[VZ]);
+			  }
+			  if (!spinner4->hasFocus())
+			  {
+				  spinner4->setPrecision(4);
+				  spinner4->setValue(q.mQ[VS]);
+			  }
+			  break;
+		  }
 		  case TYPE_RECT:
 		  {
 			LLRect r;
diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp
index 7fcd6f4361c83f4eeabe918df98ab3ce807931ff..79fafade2d2489cefd87d6ebb70644315824ac11 100644
--- a/indra/newview/lljoystickbutton.cpp
+++ b/indra/newview/lljoystickbutton.cpp
@@ -37,6 +37,7 @@
 #include "llui.h"
 #include "llagent.h"
 #include "llagentcamera.h"
+#include "llviewercamera.h"
 #include "llviewertexture.h"
 #include "llviewertexturelist.h"
 #include "llviewerwindow.h"
@@ -54,6 +55,8 @@ static LLDefaultChildRegistry::Register<LLJoystickQuaternion> r6("joystick_quat"
 const F32 NUDGE_TIME = 0.25f;		// in seconds
 const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed
 
+const S32 CENTER_DOT_RADIUS = 7;
+
 //
 // Public Methods
 //
@@ -138,9 +141,25 @@ bool LLJoystick::pointInCircle(S32 x, S32 y) const
 	//center is x and y coordinates of center of joystick circle, and also its radius
 	int center = this->getLocalRect().getHeight()/2;
 	bool in_circle = (x - center) * (x - center) + (y - center) * (y - center) <= center * center;
+	
 	return in_circle;
 }
 
+bool LLJoystick::pointInCenterDot(S32 x, S32 y, S32 radius) const
+{
+	if (this->getLocalRect().getHeight() != this->getLocalRect().getWidth())
+	{
+		LL_WARNS() << "Joystick shape is not square" << LL_ENDL;
+		return true;
+	}
+
+	S32 center = this->getLocalRect().getHeight() / 2;
+
+	bool in_center_circle = (x - center) * (x - center) + (y - center) * (y - center) <= radius * radius;
+
+	return in_center_circle;
+}
+
 BOOL LLJoystick::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	//LL_INFOS() << "joystick mouse down " << x << ", " << y << LL_ENDL;
@@ -403,8 +422,11 @@ LLJoystickCameraRotate::LLJoystickCameraRotate(const LLJoystickCameraRotate::Par
 	mInLeft( FALSE ),
 	mInTop( FALSE ),
 	mInRight( FALSE ),
-	mInBottom( FALSE )
-{ }
+	mInBottom( FALSE ),
+	mInCenter( FALSE )
+{ 
+	mCenterImageName = "Cam_Rotate_Center";
+}
 
 
 void LLJoystickCameraRotate::updateSlop()
@@ -434,7 +456,16 @@ BOOL LLJoystickCameraRotate::handleMouseDown(S32 x, S32 y, MASK mask)
 	S32 dx = x - horiz_center;
 	S32 dy = y - vert_center;
 
-	if (dy > dx && dy > -dx)
+	if (pointInCenterDot(x, y, CENTER_DOT_RADIUS))
+	{
+		mInitialOffset.mX = 0;
+		mInitialOffset.mY = 0;
+		mInitialQuadrant = JQ_ORIGIN;
+		mInCenter = TRUE;
+
+		resetJoystickCamera();
+	}
+	else if (dy > dx && dy > -dx)
 	{
 		// top
 		mInitialOffset.mX = 0;
@@ -469,9 +500,20 @@ BOOL LLJoystickCameraRotate::handleMouseDown(S32 x, S32 y, MASK mask)
 BOOL LLJoystickCameraRotate::handleMouseUp(S32 x, S32 y, MASK mask)
 {
 	gAgent.setMovementLocked(FALSE);
+	mInCenter = FALSE;
 	return LLJoystick::handleMouseUp(x, y, mask);
 }
 
+BOOL LLJoystickCameraRotate::handleHover(S32 x, S32 y, MASK mask)
+{
+	if (!pointInCenterDot(x, y, CENTER_DOT_RADIUS))
+	{
+		mInCenter = FALSE;
+	}
+
+	return LLJoystick::handleHover(x, y, mask);
+}
+
 void LLJoystickCameraRotate::onHeldDown()
 {
 	updateSlop();
@@ -504,6 +546,11 @@ void LLJoystickCameraRotate::onHeldDown()
 	}
 }
 
+void LLJoystickCameraRotate::resetJoystickCamera()
+{
+	gAgentCamera.resetCameraOrbit();
+}
+
 F32 LLJoystickCameraRotate::getOrbitRate()
 {
 	F32 time = getElapsedHeldDownTime();
@@ -536,24 +583,31 @@ void LLJoystickCameraRotate::draw()
 	getImageUnselected()->draw( 0, 0 );
 	LLPointer<LLUIImage> image = getImageSelected();
 
-	if( mInTop )
+	if (mInCenter)
 	{
-		drawRotatedImage( getImageSelected(), 0 );
+		drawRotatedImage(LLUI::getUIImage(mCenterImageName), 0);
 	}
-
-	if( mInRight )
+	else
 	{
-		drawRotatedImage( getImageSelected(), 1 );
-	}
+		if (mInTop)
+		{
+			drawRotatedImage(getImageSelected(), 0);
+		}
 
-	if( mInBottom )
-	{
-		drawRotatedImage( getImageSelected(), 2 );
-	}
+		if (mInRight)
+		{
+			drawRotatedImage(getImageSelected(), 1);
+		}
 
-	if( mInLeft )
-	{
-		drawRotatedImage( getImageSelected(), 3 );
+		if (mInBottom)
+		{
+			drawRotatedImage(getImageSelected(), 2);
+		}
+
+		if (mInLeft)
+		{
+			drawRotatedImage(getImageSelected(), 3);
+		}
 	}
 }
 
@@ -613,7 +667,9 @@ LLJoystickCameraTrack::Params::Params()
 
 LLJoystickCameraTrack::LLJoystickCameraTrack(const LLJoystickCameraTrack::Params& p)
 :	LLJoystickCameraRotate(p)
-{}
+{
+	mCenterImageName = "Cam_Tracking_Center";
+}
 
 
 void LLJoystickCameraTrack::onHeldDown()
@@ -647,6 +703,11 @@ void LLJoystickCameraTrack::onHeldDown()
 	}
 }
 
+void LLJoystickCameraTrack::resetJoystickCamera()
+{
+	gAgentCamera.resetCameraPan();
+}
+
 //-------------------------------------------------------------------------------
 // LLJoystickQuaternion
 //-------------------------------------------------------------------------------
diff --git a/indra/newview/lljoystickbutton.h b/indra/newview/lljoystickbutton.h
index ee66088b560e77aa1275438263a7f545f5b669e5..b7fdf63e583b4f61e525c5e2b79146053bc134d5 100644
--- a/indra/newview/lljoystickbutton.h
+++ b/indra/newview/lljoystickbutton.h
@@ -80,7 +80,8 @@ class LLJoystick
 	 * Image containing circle is square and this square has adherent points with joystick
 	 * circle. Make sure to change method according to shape other than square. 
 	 */
-	bool			pointInCircle(S32 x, S32 y) const;
+	bool	pointInCircle(S32 x, S32 y) const;
+	bool	pointInCenterDot(S32 x, S32 y, S32 radius) const;
 	
 	static std::string nameFromQuadrant(const EJoystickQuadrant quadrant);
 	static EJoystickQuadrant quadrantFromName(const std::string& name);
@@ -148,7 +149,9 @@ class LLJoystickCameraRotate
 
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
+	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
 	virtual void	onHeldDown();
+	virtual void	resetJoystickCamera();
 	virtual void	draw();
 
 protected:
@@ -161,6 +164,9 @@ class LLJoystickCameraRotate
 	BOOL			mInTop;
 	BOOL			mInRight;
 	BOOL			mInBottom;
+	BOOL			mInCenter;
+
+	std::string		mCenterImageName;
 };
 
 
@@ -177,6 +183,7 @@ class LLJoystickCameraTrack
 
 	LLJoystickCameraTrack(const LLJoystickCameraTrack::Params&);
 	virtual void	onHeldDown();
+	virtual void	resetJoystickCamera();
 };
 
 // 
diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index b654e928e2effb2ae4cd04f0c10a71d648bab450..02911313ed41784d3fd020f08a552c560498ea23 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -66,9 +66,6 @@ extern LLControlGroup gSavedSettings;
 static const LLUUID PARCEL_MEDIA_LIST_ITEM_UUID = LLUUID("CAB5920F-E484-4233-8621-384CF373A321");
 static const LLUUID PARCEL_AUDIO_LIST_ITEM_UUID = LLUUID("DF4B020D-8A24-4B95-AB5D-CA970D694822");
 
-const F32 AUTO_CLOSE_FADE_TIME_START= 2.0f;
-const F32 AUTO_CLOSE_FADE_TIME_END = 3.0f;
-
 //
 // LLPanelNearByMedia
 //
@@ -82,8 +79,6 @@ LLPanelNearByMedia::LLPanelNearByMedia()
 	  mParcelMediaItem(NULL),
 	  mParcelAudioItem(NULL)
 {
-	mHoverTimer.stop();
-
     // This is just an initial value, mParcelAudioAutoStart does not affect ParcelMediaAutoPlayEnable
     mParcelAudioAutoStart = gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0
                             && gSavedSettings.getBOOL("MediaTentativeAutoPlay");
@@ -111,7 +106,7 @@ LLPanelNearByMedia::~LLPanelNearByMedia()
 
 BOOL LLPanelNearByMedia::postBuild()
 {
-	LLPanel::postBuild();
+	LLPanelPulldown::postBuild();
 
 	const S32 RESIZE_BAR_THICKNESS = 6;
 	LLResizeBar::Params p;
@@ -193,45 +188,10 @@ void LLPanelNearByMedia::handleMediaAutoPlayChanged(const LLSD& newvalue)
     inst->cancelNotification();
 }
 
-/*virtual*/
-void LLPanelNearByMedia::onMouseEnter(S32 x, S32 y, MASK mask)
-{
-	mHoverTimer.stop();
-	LLPanel::onMouseEnter(x,y,mask);
-}
-
-
-/*virtual*/
-void LLPanelNearByMedia::onMouseLeave(S32 x, S32 y, MASK mask)
-{
-	mHoverTimer.start();
-	LLPanel::onMouseLeave(x,y,mask);
-}
-
-/*virtual*/ 
-void LLPanelNearByMedia::onTopLost()
-{
-	setVisible(FALSE);
-}
-
-
-/*virtual*/ 
-void LLPanelNearByMedia::onVisibilityChange ( BOOL new_visibility )
-{
-	if (new_visibility)	
-	{
-		mHoverTimer.start(); // timer will be stopped when mouse hovers over panel
-	}
-	else
-	{
-		mHoverTimer.stop();
-	}
-}
-
 /*virtual*/
 void LLPanelNearByMedia::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
-	LLPanel::reshape(width, height, called_from_parent);
+	LLPanelPulldown::reshape(width, height, called_from_parent);
 
 	LLButton* more_btn = findChild<LLButton>("more_btn");
 	if (more_btn && more_btn->getValue().asBoolean())
@@ -255,24 +215,14 @@ void LLPanelNearByMedia::draw()
 
 	refreshList();
 	updateControls();
-	
-	F32 alpha = mHoverTimer.getStarted() 
-		? clamp_rescale(mHoverTimer.getElapsedTimeF32(), AUTO_CLOSE_FADE_TIME_START, AUTO_CLOSE_FADE_TIME_END, 1.f, 0.f)
-		: 1.0f;
-	LLViewDrawContext context(alpha);
 
-	LLPanel::draw();
-
-	if (alpha == 0.f)
-	{
-		setVisible(false);
-	}
+	LLPanelPulldown::draw();
 }
 
 /*virtual*/
 BOOL LLPanelNearByMedia::handleHover(S32 x, S32 y, MASK mask)
 {
-	LLPanel::handleHover(x, y, mask);
+	LLPanelPulldown::handleHover(x, y, mask);
 	
 	// If we are hovering over this panel, make sure to clear any hovered media
 	// ID.  Note that the more general solution would be to clear this ID when
diff --git a/indra/newview/llpanelnearbymedia.h b/indra/newview/llpanelnearbymedia.h
index a9c1b190cfb1ae0c6f7cde07c0d7648bd087ad30..2d898d0aa1e08f8a8a788b03dbac336fb3d761bf 100644
--- a/indra/newview/llpanelnearbymedia.h
+++ b/indra/newview/llpanelnearbymedia.h
@@ -27,7 +27,7 @@
 #ifndef LL_LLPANELNEARBYMEDIA_H
 #define LL_LLPANELNEARBYMEDIA_H
 
-#include "llpanel.h"
+#include "llpanelpulldown.h"
 
 class LLPanelNearbyMedia;
 class LLButton;
@@ -39,16 +39,12 @@ class LLTextBox;
 class LLComboBox;
 class LLViewerMediaImpl;
 
-class LLPanelNearByMedia : public LLPanel
+class LLPanelNearByMedia : public LLPanelPulldown
 {
 public:
 	
 	/*virtual*/ BOOL postBuild();
 	/*virtual*/ void draw();
-	/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
-	/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
-	/*virtual*/ void onTopLost();
-	/*virtual*/ void onVisibilityChange ( BOOL new_visibility );
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
 	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
 
@@ -173,7 +169,6 @@ class LLPanelNearByMedia : public LLPanel
 	
 	LLRect				mMoreRect;
 	LLRect				mLessRect;
-	LLFrameTimer		mHoverTimer;
 	LLScrollListItem*	mParcelMediaItem;
 	LLScrollListItem*	mParcelAudioItem;
 };
diff --git a/indra/newview/llpanelpresetscamerapulldown.cpp b/indra/newview/llpanelpresetscamerapulldown.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..183123e534e8a333472d94117ae9475e3d203c12
--- /dev/null
+++ b/indra/newview/llpanelpresetscamerapulldown.cpp
@@ -0,0 +1,149 @@
+/** 
+ * @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 "llfloatercamera.h"
+#include "llfloaterreg.h"
+#include "llfloaterpreference.h"
+#include "llpresetsmanager.h"
+#include "llsliderctrl.h"
+#include "llscrolllistctrl.h"
+#include "lltrans.h"
+
+///----------------------------------------------------------------------------
+/// Class LLPanelPresetsCameraPulldown
+///----------------------------------------------------------------------------
+
+// Default constructor
+LLPanelPresetsCameraPulldown::LLPanelPresetsCameraPulldown()
+{
+	mCommitCallbackRegistrar.add("Presets.toggleCameraFloater", 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)
+	{
+		// Make sure there is a default preference file
+		presetsMgr->createMissingDefault(PRESETS_CAMERA);
+
+		presetsMgr->startWatching(PRESETS_CAMERA);
+
+		presetsMgr->setPresetListChangeCameraCallback(boost::bind(&LLPanelPresetsCameraPulldown::populatePanel, this));
+	}
+
+	populatePanel();
+
+	return LLPanelPulldown::postBuild();
+}
+
+void LLPanelPresetsCameraPulldown::populatePanel()
+{
+	LLPresetsManager::getInstance()->loadPresetNamesFromDir(PRESETS_CAMERA, mPresetNames, DEFAULT_BOTTOM);
+
+	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);
+		}
+	}
+}
+
+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;
+			LLFloaterCamera::switchToPreset(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);
+
+	LLFloaterReg::toggleInstanceOrBringToFront("camera");
+}
diff --git a/indra/newview/llpanelpresetscamerapulldown.h b/indra/newview/llpanelpresetscamerapulldown.h
new file mode 100644
index 0000000000000000000000000000000000000000..c49bab042e22d8ba89871471865c7b7a53d10b0d
--- /dev/null
+++ b/indra/newview/llpanelpresetscamerapulldown.h
@@ -0,0 +1,49 @@
+/** 
+ * @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 "llpanelpulldown.h"
+
+class LLPanelPresetsCameraPulldown : public LLPanelPulldown
+{
+ public:
+	LLPanelPresetsCameraPulldown();
+	/*virtual*/ BOOL postBuild();
+	void populatePanel();
+	
+ private:
+	void onViewButtonClick(const LLSD& user_data);
+	void onRowClick(const LLSD& user_data);
+
+	std::list<std::string> mPresetNames;
+    LOG_CLASS(LLPanelPresetsCameraPulldown);
+};
+
+#endif // LL_LLPANELPRESETSCAMERAPULLDOWN_H
diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp
index 9b4dc5474a08e644ed0121935862e91ebb848958..aa5ba3f210ea5ccef5052e366ec59db0a6b6d934 100644
--- a/indra/newview/llpanelpresetspulldown.cpp
+++ b/indra/newview/llpanelpresetspulldown.cpp
@@ -40,9 +40,6 @@
 #include "llscrolllistctrl.h"
 #include "lltrans.h"
 
-/* static */ const F32 LLPanelPresetsPulldown::sAutoCloseFadeStartTimeSec = 2.0f;
-/* static */ const F32 LLPanelPresetsPulldown::sAutoCloseTotalTimeSec = 3.0f;
-
 ///----------------------------------------------------------------------------
 /// Class LLPanelPresetsPulldown
 ///----------------------------------------------------------------------------
@@ -63,17 +60,16 @@ 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();
 
-	return LLPanel::postBuild();
+	return LLPanelPulldown::postBuild();
 }
 
 void LLPanelPresetsPulldown::populatePanel()
 {
-	std::string presets_dir = LLPresetsManager::getInstance()->getPresetsDir(PRESETS_GRAPHIC);
-	LLPresetsManager::getInstance()->loadPresetNamesFromDir(presets_dir, mPresetNames, DEFAULT_TOP);
+	LLPresetsManager::getInstance()->loadPresetNamesFromDir(PRESETS_GRAPHIC, mPresetNames, DEFAULT_TOP);
 
 	LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("preset_list");
 
@@ -112,61 +108,6 @@ void LLPanelPresetsPulldown::populatePanel()
 	}
 }
 
-/*virtual*/
-void LLPanelPresetsPulldown::onMouseEnter(S32 x, S32 y, MASK mask)
-{
-	mHoverTimer.stop();
-	LLPanel::onMouseEnter(x,y,mask);
-}
-
-/*virtual*/
-void LLPanelPresetsPulldown::onTopLost()
-{
-	setVisible(FALSE);
-}
-
-/*virtual*/
-BOOL LLPanelPresetsPulldown::handleMouseDown(S32 x, S32 y, MASK mask)
-{
-    LLPanel::handleMouseDown(x,y,mask);
-    return TRUE;
-}
-
-/*virtual*/
-BOOL LLPanelPresetsPulldown::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
-    LLPanel::handleRightMouseDown(x, y, mask);
-    return TRUE;
-}
-
-/*virtual*/
-BOOL LLPanelPresetsPulldown::handleDoubleClick(S32 x, S32 y, MASK mask)
-{
-    LLPanel::handleDoubleClick(x, y, mask);
-    return TRUE;
-}
-
-/*virtual*/
-void LLPanelPresetsPulldown::onMouseLeave(S32 x, S32 y, MASK mask)
-{
-	mHoverTimer.start();
-	LLPanel::onMouseLeave(x,y,mask);
-}
-
-/*virtual*/ 
-void LLPanelPresetsPulldown::onVisibilityChange ( BOOL new_visibility )
-{
-	if (new_visibility)	
-	{
-		mHoverTimer.start(); // timer will be stopped when mouse hovers over panel
-	}
-	else
-	{
-		mHoverTimer.stop();
-
-	}
-}
-
 void LLPanelPresetsPulldown::onRowClick(const LLSD& user_data)
 {
 	LLScrollListCtrl* scroll = getChild<LLScrollListCtrl>("preset_list");
@@ -213,19 +154,3 @@ void LLPanelPresetsPulldown::onGraphicsButtonClick(const LLSD& user_data)
 		}
 	}
 }
-
-//virtual
-void LLPanelPresetsPulldown::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/llpanelpresetspulldown.h b/indra/newview/llpanelpresetspulldown.h
index 322bf5a58f5414bf54624677d3d6d7aae825daa3..c0d32b9b21a4df5300efc26c9cf24f19ece191fb 100644
--- a/indra/newview/llpanelpresetspulldown.h
+++ b/indra/newview/llpanelpresetspulldown.h
@@ -29,22 +29,13 @@
 
 #include "linden_common.h"
 
-#include "llpanel.h"
+#include "llpanelpulldown.h"
 
-class LLFrameTimer;
 
-class LLPanelPresetsPulldown : public LLPanel
+class LLPanelPresetsPulldown : public LLPanelPulldown
 {
  public:
 	LLPanelPresetsPulldown();
-	/*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();
 	
@@ -53,9 +44,6 @@ class LLPanelPresetsPulldown : public LLPanel
 	void onRowClick(const LLSD& user_data);
 
 	std::list<std::string> mPresetNames;
-	LLFrameTimer mHoverTimer;
-	static const F32 sAutoCloseFadeStartTimeSec;
-	static const F32 sAutoCloseTotalTimeSec;
     LOG_CLASS(LLPanelPresetsPulldown);
 };
 
diff --git a/indra/newview/llpanelpulldown.cpp b/indra/newview/llpanelpulldown.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4de6ee81829eadd0910a13d049d02035a70bbbba
--- /dev/null
+++ b/indra/newview/llpanelpulldown.cpp
@@ -0,0 +1,118 @@
+/**
+* @file llpanelpulldown.cpp
+* @brief A panel that serves as a basis for multiple toolbar pulldown panels
+*
+* $LicenseInfo:firstyear=2020&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2020, 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 "llpanelpulldown.h"
+
+const F32 AUTO_CLOSE_FADE_TIME_START_SEC = 2.0f;
+const F32 AUTO_CLOSE_FADE_TIME_END_SEC = 3.0f;
+
+///----------------------------------------------------------------------------
+/// Class LLPanelPresetsCameraPulldown
+///----------------------------------------------------------------------------
+
+// Default constructor
+LLPanelPulldown::LLPanelPulldown()
+{
+    mHoverTimer.stop();
+}
+
+/*virtual*/
+void LLPanelPulldown::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+    mHoverTimer.stop();
+    LLPanel::onMouseEnter(x, y, mask);
+}
+
+/*virtual*/
+void LLPanelPulldown::onTopLost()
+{
+    setVisible(FALSE);
+}
+
+/*virtual*/
+BOOL LLPanelPulldown::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+    LLPanel::handleMouseDown(x, y, mask);
+    return TRUE;
+}
+
+/*virtual*/
+BOOL LLPanelPulldown::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+    LLPanel::handleRightMouseDown(x, y, mask);
+    return TRUE;
+}
+
+/*virtual*/
+BOOL LLPanelPulldown::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+    LLPanel::handleDoubleClick(x, y, mask);
+    return TRUE;
+}
+
+BOOL LLPanelPulldown::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+    LLPanel::handleScrollWheel(x, y, clicks);
+    return TRUE; //If we got here, then we are in Pulldown's rect, consume the event.
+}
+
+/*virtual*/
+void LLPanelPulldown::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+    mHoverTimer.start();
+    LLPanel::onMouseLeave(x, y, mask);
+}
+
+/*virtual*/
+void LLPanelPulldown::onVisibilityChange(BOOL new_visibility)
+{
+    if (new_visibility)
+    {
+        mHoverTimer.start(); // timer will be stopped when mouse hovers over panel
+    }
+    else
+    {
+        mHoverTimer.stop();
+    }
+}
+
+//virtual
+void LLPanelPulldown::draw()
+{
+    F32 alpha = mHoverTimer.getStarted()
+        ? clamp_rescale(mHoverTimer.getElapsedTimeF32(), AUTO_CLOSE_FADE_TIME_START_SEC, AUTO_CLOSE_FADE_TIME_END_SEC, 1.f, 0.f)
+        : 1.0f;
+    LLViewDrawContext context(alpha);
+
+    LLPanel::draw();
+
+    if (alpha == 0.f)
+    {
+        setVisible(FALSE);
+    }
+}
diff --git a/indra/newview/llpanelpulldown.h b/indra/newview/llpanelpulldown.h
new file mode 100644
index 0000000000000000000000000000000000000000..705e76d0ab2556771806218d07aa790b731b429b
--- /dev/null
+++ b/indra/newview/llpanelpulldown.h
@@ -0,0 +1,55 @@
+/** 
+ * @file llpanelpulldown.h
+ * @brief A panel that serves as a basis for multiple toolbar pulldown panels
+ *
+ * $LicenseInfo:firstyear=2020&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2020, 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_LLPANELPULLDOWN_H
+#define LL_LLPANELPULLDOWN_H
+
+#include "linden_common.h"
+
+#include "llpanel.h"
+
+class LLFrameTimer;
+
+class LLPanelPulldown : public LLPanel
+{
+public:
+    LLPanelPulldown();
+    /*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*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+    /*virtual*/ void onTopLost();
+    /*virtual*/ void onVisibilityChange(BOOL new_visibility);
+
+    /*virtual*/ void draw();
+
+protected:
+    LLFrameTimer mHoverTimer;
+};
+
+#endif // LL_LLPANELPULLDOWN_H
diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp
index f063d8427283b670a1f732f8691b9947e3040de3..6f11e76a72d304fa5923bd5fcf20371ac5a04552 100644
--- a/indra/newview/llpanelvolumepulldown.cpp
+++ b/indra/newview/llpanelvolumepulldown.cpp
@@ -41,9 +41,6 @@
 #include "llfloaterpreference.h"
 #include "llsliderctrl.h"
 
-/* static */ const F32 LLPanelVolumePulldown::sAutoCloseFadeStartTimeSec = 2.0f;
-/* static */ const F32 LLPanelVolumePulldown::sAutoCloseTotalTimeSec = 3.0f;
-
 ///----------------------------------------------------------------------------
 /// Class LLPanelVolumePulldown
 ///----------------------------------------------------------------------------
@@ -51,8 +48,6 @@
 // Default constructor
 LLPanelVolumePulldown::LLPanelVolumePulldown()
 {
-	mHoverTimer.stop();
-
 	mCommitCallbackRegistrar.add("Vol.setControlFalse", boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2));
 	mCommitCallbackRegistrar.add("Vol.SetSounds", boost::bind(&LLPanelVolumePulldown::onClickSetSounds, this));
 	mCommitCallbackRegistrar.add("Vol.updateMediaAutoPlayCheckbox",	boost::bind(&LLPanelVolumePulldown::updateMediaAutoPlayCheckbox, this, _1));
@@ -62,41 +57,7 @@ LLPanelVolumePulldown::LLPanelVolumePulldown()
 
 BOOL LLPanelVolumePulldown::postBuild()
 {
-	return LLPanel::postBuild();
-}
-
-/*virtual*/
-void LLPanelVolumePulldown::onMouseEnter(S32 x, S32 y, MASK mask)
-{
-	mHoverTimer.stop();
-	LLPanel::onMouseEnter(x,y,mask);
-}
-
-/*virtual*/
-void LLPanelVolumePulldown::onTopLost()
-{
-	setVisible(FALSE);
-}
-
-/*virtual*/
-void LLPanelVolumePulldown::onMouseLeave(S32 x, S32 y, MASK mask)
-{
-	mHoverTimer.start();
-	LLPanel::onMouseLeave(x,y,mask);
-}
-
-/*virtual*/ 
-void LLPanelVolumePulldown::onVisibilityChange ( BOOL new_visibility )
-{
-	if (new_visibility)	
-	{
-		mHoverTimer.start(); // timer will be stopped when mouse hovers over panel
-	}
-	else
-	{
-		mHoverTimer.stop();
-
-	}
+	return LLPanelPulldown::postBuild();
 }
 
 void LLPanelVolumePulldown::onAdvancedButtonClick(const LLSD& user_data)
@@ -150,20 +111,3 @@ void LLPanelVolumePulldown::onClickSetSounds()
 	// or if sound effects are disabled.
 	getChild<LLCheckBoxCtrl>("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds"));
 }
-
-//virtual
-void LLPanelVolumePulldown::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/llpanelvolumepulldown.h b/indra/newview/llpanelvolumepulldown.h
index 4f23112f5000112a43a4206dd7679cb35201237f..e907bb0c78fa36dbd4623c8187a14bc39d2e0799 100644
--- a/indra/newview/llpanelvolumepulldown.h
+++ b/indra/newview/llpanelvolumepulldown.h
@@ -30,19 +30,12 @@
 
 #include "linden_common.h"
 
-#include "llpanel.h"
+#include "llpanelpulldown.h"
 
-class LLFrameTimer;
-
-class LLPanelVolumePulldown : public LLPanel
+class LLPanelVolumePulldown : public LLPanelPulldown
 {
  public:
 	LLPanelVolumePulldown();
-	/*virtual*/ void draw();
-	/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
-	/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
-	/*virtual*/ void onTopLost();
-	/*virtual*/ void onVisibilityChange ( BOOL new_visibility );
 	/*virtual*/ BOOL postBuild();
 	
  private:
@@ -52,10 +45,6 @@ class LLPanelVolumePulldown : public LLPanel
 	// "Streaming Music" and "Media" are unchecked. Otherwise enables it.
 	void updateMediaAutoPlayCheckbox(LLUICtrl* ctrl);
 	void onAdvancedButtonClick(const LLSD& user_data);
-
-	LLFrameTimer mHoverTimer;
-	static const F32 sAutoCloseFadeStartTimeSec;
-	static const F32 sAutoCloseTotalTimeSec;
 };
 
 
diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp
index df93572508283b925c5caf22388adbd6a764dc7f..c267c3c699520752b8d15dfc8453a153fec088dc 100644
--- a/indra/newview/llpresetsmanager.cpp
+++ b/indra/newview/llpresetsmanager.cpp
@@ -39,6 +39,8 @@
 #include "llfloaterpreference.h"
 #include "llfloaterreg.h"
 #include "llfeaturemanager.h"
+#include "llagentcamera.h"
+#include "llfile.h"
 
 LLPresetsManager::LLPresetsManager()
 {
@@ -46,6 +48,12 @@ LLPresetsManager::LLPresetsManager()
 
 LLPresetsManager::~LLPresetsManager()
 {
+	mCameraChangedSignal.disconnect();
+}
+
+void LLPresetsManager::triggerChangeCameraSignal()
+{
+	mPresetListChangeCameraSignal();
 }
 
 void LLPresetsManager::triggerChangeSignal()
@@ -53,41 +61,92 @@ void LLPresetsManager::triggerChangeSignal()
 	mPresetListChangeSignal();
 }
 
-void LLPresetsManager::createMissingDefault()
+void LLPresetsManager::createMissingDefault(const std::string& subdirectory)
 {
 	if(gDirUtilp->getLindenUserDir().empty())
 	{
 		return;
 	}
-	std::string default_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, PRESETS_GRAPHIC, PRESETS_DEFAULT + ".xml");
+
+	if (PRESETS_CAMERA == subdirectory)
+	{
+		createCameraDefaultPresets();
+		return;
+	}
+
+	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
+	{
+		LL_DEBUGS() << "default preset exists; no-op" << LL_ENDL;
+	}
+}
+
+void LLPresetsManager::createCameraDefaultPresets()
+{
+	bool is_default_created = createDefaultCameraPreset(PRESETS_REAR_VIEW);
+	is_default_created |= createDefaultCameraPreset(PRESETS_FRONT_VIEW);
+	is_default_created |= createDefaultCameraPreset(PRESETS_SIDE_VIEW);
+
+	if (is_default_created)
+	{
+		triggerChangeCameraSignal();
+	}
+}
+
+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;
+			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));
+				}
+			}
+		}
 	}
-    else
-    {
-        LL_DEBUGS() << "default preset exists; no-op" << LL_ENDL;
-    }
 }
 
 std::string LLPresetsManager::getPresetsDir(const std::string& subdirectory)
 {
 	std::string presets_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR);
-	std::string full_path;
 
 	LLFile::mkdir(presets_path);
 
-	full_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, subdirectory);
-	LLFile::mkdir(full_path);
+	std::string dest_path = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, subdirectory);
+	if (!gDirUtilp->fileExists(dest_path))
+		LLFile::mkdir(dest_path);
 
-	return full_path;
+	return dest_path;
 }
 
-void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_name_list_t& presets, EDefaultOptions default_option)
+void LLPresetsManager::loadPresetNamesFromDir(const std::string& subdirectory, preset_name_list_t& presets, EDefaultOptions default_option)
 {
+	bool IS_CAMERA = (PRESETS_CAMERA == subdirectory);
+	bool IS_GRAPHIC = (PRESETS_GRAPHIC == subdirectory);
+
+	std::string dir = LLPresetsManager::getInstance()->getPresetsDir(subdirectory);
 	LL_INFOS("AppInit") << "Loading list of preset names from " << dir << LL_ENDL;
 
 	mPresetNames.clear();
@@ -103,16 +162,33 @@ void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_nam
 		{
 			std::string path = gDirUtilp->add(dir, file);
 			std::string name = LLURI::unescape(gDirUtilp->getBaseFileName(path, /*strip_exten = */ true));
-            LL_DEBUGS() << "  Found preset '" << name << "'" << LL_ENDL;
+			LL_DEBUGS() << "  Found preset '" << name << "'" << LL_ENDL;
 
-			if (PRESETS_DEFAULT != name)
+			if (IS_CAMERA)
 			{
+				if (isTemplateCameraPreset(name))
+				{
+					continue;
+				}
+				if ((default_option == DEFAULT_HIDE) || (default_option == DEFAULT_BOTTOM))
+				{
+					if (isDefaultCameraPreset(name))
+					{
+						continue;
+					}
+				}
 				mPresetNames.push_back(name);
 			}
-			else
+			if (IS_GRAPHIC)
 			{
-				switch (default_option)
+				if (PRESETS_DEFAULT != name)
 				{
+					mPresetNames.push_back(name);
+				}
+				else
+				{
+					switch (default_option)
+					{
 					case DEFAULT_SHOW:
 						mPresetNames.push_back(LLTrans::getString(PRESETS_DEFAULT));
 						break;
@@ -124,16 +200,77 @@ void LLPresetsManager::loadPresetNamesFromDir(const std::string& dir, preset_nam
 					case DEFAULT_HIDE:
 					default:
 						break;
+					}
 				}
 			}
 		}
 	}
 
+	if (IS_CAMERA)
+	{
+		mPresetNames.sort(LLStringUtil::precedesDict);
+		if (default_option == DEFAULT_BOTTOM)
+		{
+			mPresetNames.push_back(PRESETS_FRONT_VIEW);
+			mPresetNames.push_back(PRESETS_REAR_VIEW);
+			mPresetNames.push_back(PRESETS_SIDE_VIEW);
+		}
+	}
+
 	presets = mPresetNames;
 }
 
+bool LLPresetsManager::mCameraDirty = false;
+bool LLPresetsManager::mIgnoreChangedSignal = false;
+
+void LLPresetsManager::setCameraDirty(bool dirty)
+{
+	mCameraDirty = dirty;
+}
+
+bool LLPresetsManager::isCameraDirty()
+{
+	return mCameraDirty;
+}
+
+void LLPresetsManager::settingChanged()
+{
+	setCameraDirty(true);
+
+	static LLCachedControl<std::string> preset_camera_active(gSavedSettings, "PresetCameraActive", "");
+	std::string preset_name = preset_camera_active;
+	if (!preset_name.empty() && !mIgnoreChangedSignal)
+	{
+		gSavedSettings.setString("PresetCameraActive", "");
+
+		// Hack call because this is a static routine
+		LLPresetsManager::getInstance()->triggerChangeCameraSignal();
+	}
+}
+
+void LLPresetsManager::getControlNames(std::vector<std::string>& names)
+{
+	const std::vector<std::string> camera_controls = boost::assign::list_of
+		// From panel_preferences_move.xml
+		("CameraAngle")
+		("CameraOffsetScale")
+		("EditCameraMovement")
+		("AppearanceCameraMovement")
+		// From llagentcamera.cpp
+		("CameraOffsetBuild")
+		("TrackFocusObject")
+		("CameraOffsetRearView")
+		("FocusOffsetRearView")
+		("AvatarSitRotation")
+        ;
+    names = camera_controls;
+}
+
 bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string name, bool createDefault)
 {
+	bool IS_CAMERA = (PRESETS_CAMERA == subdirectory);
+	bool IS_GRAPHIC = (PRESETS_GRAPHIC == subdirectory);
+
 	if (LLTrans::getString(PRESETS_DEFAULT) == name)
 	{
 		name = PRESETS_DEFAULT;
@@ -144,126 +281,174 @@ bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string n
 		return false;
 	}
 
+	if (isTemplateCameraPreset(name))
+	{
+		LL_WARNS() << "Should not overwrite template presets" << LL_ENDL;
+		return false;
+	}
+
 	bool saved = false;
 	std::vector<std::string> name_list;
 
-	if(PRESETS_GRAPHIC == subdirectory)
+	if (IS_GRAPHIC)
 	{
 		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("Presets") << "preferences floater instance not found" << LL_ENDL;
+		}
 	}
-    else if(PRESETS_CAMERA == subdirectory)
+	else if (IS_CAMERA)
 	{
 		name_list.clear();
-		name_list.push_back("Placeholder");
+		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 (IS_GRAPHIC && createDefault && name == PRESETS_DEFAULT)
+	{
+		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
+	{
+		ECameraPreset new_camera_preset = (ECameraPreset)gSavedSettings.getU32("CameraPresetType");
+		bool new_camera_offsets = false;
+		if (IS_CAMERA)
+		{
+			if (isDefaultCameraPreset(name))
+			{
+				if (PRESETS_REAR_VIEW == name)
+				{
+					new_camera_preset = CAMERA_PRESET_REAR_VIEW;
+				}
+				else if (PRESETS_SIDE_VIEW == name)
+				{
+					new_camera_preset = CAMERA_PRESET_GROUP_VIEW;
+				}
+				else if (PRESETS_FRONT_VIEW == name)
+				{
+					new_camera_preset = CAMERA_PRESET_FRONT_VIEW;
+				}
+			}
+			else 
+			{
+				new_camera_preset = CAMERA_PRESET_CUSTOM;
+			}
+			new_camera_offsets = (!isDefaultCameraPreset(name) || (ECameraPreset)gSavedSettings.getU32("CameraPresetType") != new_camera_preset);
+		}
+		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();
+			if (ctrl)
+			{
+				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;
+			}
+		}
+		if (IS_CAMERA)
+		{
+			gSavedSettings.setU32("CameraPresetType", new_camera_preset);
+		}
+	}
+
+	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 (IS_GRAPHIC)
+			{
+				gSavedSettings.setString("PresetGraphicActive", name);
+				// signal interested parties
+				triggerChangeSignal();
+			}
+
+			if (IS_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();
+	combo->setEnabled(TRUE);
 
-	std::string presets_dir = getPresetsDir(subdirectory);
+	std::list<std::string> preset_names;
+	loadPresetNamesFromDir(subdirectory, preset_names, default_option);
 
-	if (!presets_dir.empty())
+	if (preset_names.begin() != preset_names.end())
 	{
-		std::list<std::string> preset_names;
-		loadPresetNamesFromDir(presets_dir, preset_names, default_option);
-
-		std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive");
-
-		if (preset_names.begin() != preset_names.end())
-		{
-			for (std::list<std::string>::const_iterator it = preset_names.begin(); it != preset_names.end(); ++it)
-			{
-				const std::string& name = *it;
-				combo->add(name, LLSD().with(0, name));
-			}
-		}
-		else
+		for (std::list<std::string>::const_iterator it = preset_names.begin(); it != preset_names.end(); ++it)
 		{
-			combo->setLabel(LLTrans::getString("preset_combo_label"));
+			const std::string& name = *it;
+			combo->add(name, name);
 		}
 	}
+	else
+	{
+		combo->setLabel(LLTrans::getString("preset_combo_label"));
+		combo->setEnabled(PRESETS_CAMERA != subdirectory);
+		sts = false;
+	}
+
+	return sts;
 }
 
 void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string name)
@@ -277,24 +462,32 @@ void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string n
 
     LL_DEBUGS() << "attempting to load preset '"<<name<<"' from '"<<full_path<<"'" << LL_ENDL;
 
+	mIgnoreChangedSignal = true;
 	if(gSavedSettings.loadFromFile(full_path, false, true) > 0)
 	{
+		mIgnoreChangedSignal = false;
 		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
-    {
-        LL_WARNS() << "failed to load preset '"<<name<<"' from '"<<full_path<<"'" << LL_ENDL;
-    }
+	else
+	{
+		mIgnoreChangedSignal = false;
+		LL_WARNS("Presets") << "failed to load preset '"<<name<<"' from '"<<full_path<<"'" << LL_ENDL;
+	}
 }
 
 bool LLPresetsManager::deletePreset(const std::string& subdirectory, std::string name)
@@ -320,17 +513,70 @@ 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;
 }
 
+bool LLPresetsManager::isDefaultCameraPreset(std::string preset_name)
+{
+	return (preset_name == PRESETS_REAR_VIEW || preset_name == PRESETS_SIDE_VIEW || preset_name == PRESETS_FRONT_VIEW);
+}
+
+bool LLPresetsManager::isTemplateCameraPreset(std::string preset_name)
+{
+	return (preset_name == PRESETS_REAR || preset_name == PRESETS_SIDE || preset_name == PRESETS_FRONT);
+}
+
+void LLPresetsManager::resetCameraPreset(std::string preset_name)
+{
+	if (isDefaultCameraPreset(preset_name))
+	{
+		createDefaultCameraPreset(preset_name, true);
+
+		if (gSavedSettings.getString("PresetCameraActive") == preset_name)
+		{
+			loadPreset(PRESETS_CAMERA, preset_name);
+		}
+	}
+}
+
+bool LLPresetsManager::createDefaultCameraPreset(std::string preset_name, bool force_reset)
+{
+	std::string preset_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR,
+		PRESETS_CAMERA, LLURI::escape(preset_name) + ".xml");
+	if (!gDirUtilp->fileExists(preset_file) || force_reset)
+	{
+		std::string template_name = preset_name.substr(0, preset_name.size() - PRESETS_VIEW_SUFFIX.size());
+		std::string default_template_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, PRESETS_CAMERA, template_name + ".xml");
+		return LLFile::copy(default_template_file, preset_file);
+	}
+	return false;
+}
+
+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 0014e32267ffd026a9c698e29a3dd20d8b2fb7e6..d5b384ceb9559e25052fedd444581e918ed42d79 100644
--- a/indra/newview/llpresetsmanager.h
+++ b/indra/newview/llpresetsmanager.h
@@ -36,11 +36,19 @@ static const std::string PRESETS_DEFAULT = "Default";
 static const std::string PRESETS_DIR = "presets";
 static const std::string PRESETS_GRAPHIC = "graphic";
 static const std::string PRESETS_CAMERA = "camera";
+static const std::string PRESETS_REAR = "Rear";
+static const std::string PRESETS_FRONT = "Front";
+static const std::string PRESETS_SIDE = "Side";
+static const std::string PRESETS_VIEW_SUFFIX = " View";
+static const std::string PRESETS_REAR_VIEW = PRESETS_REAR + PRESETS_VIEW_SUFFIX;
+static const std::string PRESETS_FRONT_VIEW = PRESETS_FRONT + PRESETS_VIEW_SUFFIX;
+static const std::string PRESETS_SIDE_VIEW = PRESETS_SIDE + PRESETS_VIEW_SUFFIX;
 
 enum EDefaultOptions
 {
 	DEFAULT_SHOW,
 	DEFAULT_TOP,
+	DEFAULT_BOTTOM,
 	DEFAULT_HIDE				// Do not display "Default" in a list
 };
 
@@ -54,26 +62,47 @@ 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);
-	void loadPresetNamesFromDir(const std::string& dir, preset_name_list_t& presets, EDefaultOptions default_option);
+	bool setPresetNamesInComboBox(const std::string& subdirectory, LLComboBox* combo, EDefaultOptions default_option);
+	void loadPresetNamesFromDir(const std::string& subdirectory, 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);
+
+	void createCameraDefaultPresets();
+
+	bool isTemplateCameraPreset(std::string preset_name);
+	bool isDefaultCameraPreset(std::string preset_name);
+	void resetCameraPreset(std::string preset_name);
+	bool createDefaultCameraPreset(std::string preset_name, bool force_reset = false);
 
 	// 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.
 
 	preset_name_list_t mPresetNames;
 
+	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 settingChanged();
+
+	boost::signals2::connection	mCameraChangedSignal;
+
+	static bool	mCameraDirty;
+	static bool mIgnoreChangedSignal;
 };
 
 #endif // LL_PRESETSMANAGER_H
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 7673bae725aaace68d2b2a8f52d0f05d2f5fe89a..b532d9a9b4eaa1fb765a45f19827f0b7c78f8c7c 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -71,6 +71,7 @@
 #include "llnotifications.h"
 #include "llnotificationsutil.h"
 #include "llpersistentnotificationstorage.h"
+#include "llpresetsmanager.h"
 #include "llteleporthistory.h"
 #include "llregionhandle.h"
 #include "llsd.h"
@@ -1965,6 +1966,8 @@ bool idle_startup()
 		// JC - 7/20/2002
 		gViewerWindow->sendShapeToSim();
 
+		LLPresetsManager::getInstance()->createMissingDefault(PRESETS_CAMERA);
+
 		// The reason we show the alert is because we want to
 		// reduce confusion for when you log in and your provided
 		// location is not your expected location. So, if this is
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index b8c227334da1ab21818d0fde9477abf3ead9c359..4d55448d78ae140182b35428a7f08e0ef87f29ad 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"
@@ -172,8 +173,11 @@ BOOL LLStatusBar::postBuild()
 	mBoxBalance = getChild<LLTextBox>("balance");
 	mBoxBalance->setClickedCallback( &LLStatusBar::onClickBalance, this );
 
-	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 );
@@ -228,6 +232,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);
@@ -344,7 +353,8 @@ void LLStatusBar::setVisibleForMouselook(bool visible)
 	mSGPacketLoss->setVisible(visible);
 	mSearchPanel->setVisible(visible && gSavedSettings.getBOOL("MenuSearch"));
 	setBackgroundVisible(visible);
-	mIconPresets->setVisible(visible);
+	mIconPresetsCamera->setVisible(visible);
+	mIconPresetsGraphic->setVisible(visible);
 }
 
 void LLStatusBar::debitBalance(S32 debit)
@@ -485,10 +495,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::getInstance()->clearPopups();
+	LLUI::getInstance()->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 -
@@ -527,6 +561,7 @@ void LLStatusBar::onMouseEnterVolume()
 	// show the master volume pull-down
 	LLUI::getInstance()->clearPopups();
 	LLUI::getInstance()->addPopup(mPanelVolumePulldown);
+	mPanelPresetsCameraPulldown->setVisible(FALSE);
 	mPanelPresetsPulldown->setVisible(FALSE);
 	mPanelNearByMedia->setVisible(FALSE);
 	mPanelVolumePulldown->setVisible(TRUE);
@@ -551,6 +586,7 @@ void LLStatusBar::onMouseEnterNearbyMedia()
 	LLUI::getInstance()->clearPopups();
 	LLUI::getInstance()->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 cad877f7991ed7eb42730c0a9b859c8b2e148305..3002b91c107479ec544d0e33c0003232c6f47aef 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;
@@ -99,6 +100,7 @@ class LLStatusBar
 	void onClickBuyCurrency();
 	void onVolumeChanged(const LLSD& newvalue);
 
+	void onMouseEnterPresetsCamera();
 	void onMouseEnterPresets();
 	void onMouseEnterVolume();
 	void onMouseEnterNearbyMedia();
@@ -123,7 +125,8 @@ class LLStatusBar
 	LLStatGraph *mSGBandwidth;
 	LLStatGraph *mSGPacketLoss;
 
-	LLIconCtrl	*mIconPresets;
+	LLIconCtrl	*mIconPresetsCamera;
+	LLIconCtrl	*mIconPresetsGraphic;
 	LLButton	*mBtnVolume;
 	LLTextBox	*mBoxBalance;
 	LLButton	*mMediaToggle;
@@ -135,6 +138,7 @@ class LLStatusBar
 	S32				mSquareMetersCommitted;
 	LLFrameTimer*	mBalanceTimer;
 	LLFrameTimer*	mHealthTimer;
+	LLPanelPresetsCameraPulldown* mPanelPresetsCameraPulldown;
 	LLPanelPresetsPulldown* mPanelPresetsPulldown;
 	LLPanelVolumePulldown* mPanelVolumePulldown;
 	LLPanelNearByMedia*	mPanelNearByMedia;
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index c608c589a58aa3e93493446c88a0e8928b8ccd9d..414ae1fad63688b611c735a1f1573b1e0c4f970c 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -53,6 +53,7 @@
 #include "llfloaterbuyland.h"
 #include "llfloaterbvhpreview.h"
 #include "llfloatercamera.h"
+#include "llfloatercamerapresets.h"
 #include "llfloaterchatvoicevolume.h"
 #include "llfloaterconversationlog.h"
 #include "llfloaterconversationpreview.h"
@@ -104,12 +105,14 @@
 #include "llfloaterperms.h"
 #include "llfloaterpostprocess.h"
 #include "llfloaterpreference.h"
+#include "llfloaterpreferenceviewadvanced.h"
 #include "llfloaterpreviewtrash.h"
 #include "llfloaterproperties.h"
 #include "llfloaterregiondebugconsole.h"
 #include "llfloaterregioninfo.h"
 #include "llfloaterregionrestarting.h"
 #include "llfloaterreporter.h"
+#include "llfloatersavecamerapreset.h"
 #include "llfloatersaveprefpreset.h"
 #include "llfloatersceneloadstats.h"
 #include "llfloaterscriptdebug.h"
@@ -212,6 +215,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>);
 
 	LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>);
+	LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>);
 	LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>);
 	LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater);
 	LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
@@ -299,6 +303,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);
 	LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
 	LLFloaterReg::add("prefs_graphics_advanced", "floater_preferences_graphics_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceGraphicsAdvanced>);
+	LLFloaterReg::add("prefs_view_advanced", "floater_preferences_view_advanced.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceViewAdvanced>);
 	LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>);
 	LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>);
 	LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>);
@@ -318,6 +323,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("properties", "floater_inventory_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProperties>);
 	LLFloaterReg::add("publish_classified", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPublishClassifiedFloater>);
 	LLFloaterReg::add("save_pref_preset", "floater_save_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSavePrefPreset>);
+	LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>);
 	LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptEdPrefs>);
 
 	LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build<LLFloaterTelehub>);
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index a14041717f26a52528cb46539751cd7f06da966f..6914e0fc2bcd35787062fc769cf7f784190a7bba 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -345,6 +345,7 @@ void camera_spin_around_ccw_sitting( EKeystate s )
 	else
 	{
 		//change camera but do not send keystrokes
+		gAgentCamera.unlockView();
 		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
 	}
 }
@@ -361,6 +362,7 @@ void camera_spin_around_cw_sitting( EKeystate s )
 	else
 	{
 		//change camera but do not send keystrokes
+		gAgentCamera.unlockView();
 		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
 	}
 }
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 162acb74f18098f025e50621ca4a026759057225..b6c7be2ed3550d403fc6af79fbd7111c3b824400 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -4104,8 +4104,7 @@ void handle_reset_view()
 		// switching to outfit selector should automagically save any currently edited wearable
 		LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "my_outfits"));
 	}
-
-	gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
+	
 	reset_view_final( TRUE );
 	LLFloaterCamera::resetCameraMode();
 }
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index eb461d3140c85203b81d41ebaffadc2108a16bbd..d567623ac04a64659cad560789383f2d99258af8 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -7373,7 +7373,8 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
 	mRoot->updateWorldMatrixChildren();
 
 	stopMotion(ANIM_AGENT_BODY_NOISE);
-
+	
+	gAgentCamera.setInitSitRot(gAgent.getFrameAgent().getQuaternion());
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png b/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png
new file mode 100644
index 0000000000000000000000000000000000000000..ffc3c85ea2a96cb82eeb487625eac03bb1c90aa2
Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/Cam_Rotate_Center.png differ
diff --git a/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png b/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png
new file mode 100644
index 0000000000000000000000000000000000000000..2812d614e6abc12f8f3ec1bcbad8f2f445e6f3e2
Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/Cam_Tracking_Center.png differ
diff --git a/indra/newview/skins/default/textures/icons/Presets_Icon.png b/indra/newview/skins/default/textures/icons/Presets_Icon.png
index 5a6628816b34fca5623902249385a0b7e836fd68..503ee892a55da5add034fe7055a8baf72ce64cc5 100644
Binary files a/indra/newview/skins/default/textures/icons/Presets_Icon.png and b/indra/newview/skins/default/textures/icons/Presets_Icon.png differ
diff --git a/indra/newview/skins/default/textures/icons/Presets_Icon_Graphic.png b/indra/newview/skins/default/textures/icons/Presets_Icon_Graphic.png
new file mode 100644
index 0000000000000000000000000000000000000000..5a6628816b34fca5623902249385a0b7e836fd68
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Presets_Icon_Graphic.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 624dca48d264917e9f419cb4cc51119567cbf7de..b041e6197cdc9e78b23200262e0adbd6b231b833 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -98,7 +98,7 @@ with the same filename but different name
   <texture name="BuyArrow_Over" file_name="navbar/BuyArrow_Over.png" preload="true" scale.left="0" scale.top="1" scale.right="0" scale.bottom="0"  />
   <texture name="BuyArrow_Press" file_name="navbar/BuyArrow_Press.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0"  />
 
-  <texture name="Cam_Avatar_Off" file_name="bottomtray/Cam_Avatar_Off.png" preload="false" />
+  <texture name="Cam_Avatar_Off" file_name="bottomtray/Cam_Avatar_Off.png" preload="true" />
   <texture name="Cam_FreeCam_Off" file_name="bottomtray/Cam_FreeCam_Off.png" preload="false" />
   <texture name="Cam_Orbit_Off" file_name="bottomtray/Cam_Orbit_Off.png" preload="false" />
   <texture name="Cam_Pan_Off" file_name="bottomtray/Cam_Pan_Off.png" preload="false" />
@@ -113,8 +113,10 @@ with the same filename but different name
 
   <texture name="Cam_Rotate_In" file_name="bottomtray/Cam_Rotate_In.png" preload="false" />
   <texture name="Cam_Rotate_Out" file_name="bottomtray/Cam_Rotate_Out.png" preload="false" />
+  <texture name="Cam_Rotate_Center" file_name="bottomtray/Cam_Rotate_Center.png" preload="false" />
   <texture name="Cam_Tracking_In" file_name="bottomtray/Cam_Tracking_In.png" preload="false" />
   <texture name="Cam_Tracking_Out" file_name="bottomtray/Cam_Tracking_Out.png" preload="false" />
+  <texture name="Cam_Tracking_Center" file_name="bottomtray/Cam_Tracking_Center.png" preload="false" />
 
   <texture name="Checkbox_Off_Disabled" file_name="widgets/Checkbox_Disabled.png" preload="true" />
   <texture name="Checkbox_On_Disabled" file_name="widgets/Checkbox_On_Disabled.png" preload="true" />
@@ -204,7 +206,9 @@ with the same filename but different name
 
   <texture name="Presets_Icon" file_name="icons/Presets_Icon.png" preload="true" />
 
-  <texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.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="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" />
   <texture name="Favorite_Star_Press" file_name="navbar/Favorite_Star_Press.png" preload="false" />
   <texture name="Favorite_Star_Over" file_name="navbar/Favorite_Star_Over.png" preload="false" />
@@ -253,6 +257,7 @@ with the same filename but different name
   <texture name="Icon_Gear_Background" file_name="windows/Icon_Gear_Background.png" preload="false" />
   <texture name="Icon_Gear_Foreground" file_name="windows/Icon_Gear_Foreground.png" preload="false" />
   <texture name="Icon_Gear_Press" file_name="windows/Icon_Gear_Press.png" preload="false" />
+  <texture name="Icon_Gear" file_name="windows/Icon_Gear.png" preload="false" />
 
   <texture name="Icon_Help_Foreground" file_name="windows/Icon_Help_Foreground.png" preload="true" />
   <texture name="Icon_Help_Press" file_name="windows/Icon_Help_Press.png" preload="true" />
diff --git a/indra/newview/skins/default/textures/windows/Icon_Gear.png b/indra/newview/skins/default/textures/windows/Icon_Gear.png
new file mode 100644
index 0000000000000000000000000000000000000000..e1e89b8f32dfd9c70f89d25776a587d1726871b5
Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Gear.png differ
diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml
index 72a7b5540c0fd7af9700dc68d56540d2e40449b4..9deb38e3afac6397eaee2208b771c8c14badbb8e 100644
--- a/indra/newview/skins/default/xui/en/floater_camera.xml
+++ b/indra/newview/skins/default/xui/en/floater_camera.xml
@@ -7,7 +7,7 @@
  legacy_header_height="18"
  can_minimize="true"
  can_close="true"
- height="164"
+ height="135"
  layout="topleft"
  name="camera_floater"
  help_topic="camera_floater"
@@ -16,7 +16,7 @@
  title="CAMERA CONTROLS"
  chrome="true"
  save_rect="true"
- width="228">
+ width="400">
     <floater.string
      name="rotate_tooltip">
         Rotate Camera Around Focus
@@ -33,6 +33,7 @@
      name="free_mode_title">
         View Object
     </floater.string>
+    <string name="inactive_combo_text">Use preset</string>
     <panel
      border="false"
      height="123"
@@ -41,112 +42,18 @@
      top="0"
      mouse_opaque="false"
      name="controls"
-     width="226">
-       <panel
-         follows="all"
-         height="102"
-         layout="topleft"
-         left="8"
-         name="preset_views_list"
-         top="24"
-         width="212"
-         visible="false">
-        <panel_camera_item
-          name="front_view">
-          <panel_camera_item.mousedown_callback
-            function="CameraPresets.ChangeView"
-            parameter="front_view" />
-          <panel_camera_item.picture
-            image_name="Cam_Preset_Front_Off" />
-          <panel_camera_item.selected_picture
-            image_name="Cam_Preset_Front_On" />
-          <panel_camera_item.text
-            name="front_view_text">
-            Front View
-          </panel_camera_item.text>
-        </panel_camera_item>
-        <panel_camera_item
-          name="group_view"
-          top_pad="4">
-          <panel_camera_item.mousedown_callback
-            function="CameraPresets.ChangeView"
-            parameter="group_view" />
-          <panel_camera_item.picture
-            image_name="Cam_Preset_Side_Off" />
-          <panel_camera_item.selected_picture
-            image_name="Cam_Preset_Side_On" />
-          <panel_camera_item.text
-            name="side_view_text">
-            Side View
-          </panel_camera_item.text>
-        </panel_camera_item>
-        <panel_camera_item
-          name="rear_view"
-          layout="topleft"
-          top_pad="4">
-          <panel_camera_item.mousedown_callback
-            function="CameraPresets.ChangeView"
-            parameter="rear_view" />
-          <panel_camera_item.picture
-            image_name="Cam_Preset_Back_Off" />
-          <panel_camera_item.selected_picture
-            image_name="Cam_Preset_Back_On" />
-          <panel_camera_item.text
-            name="rear_view_text">
-            Rear View
-          </panel_camera_item.text>
-        </panel_camera_item>
-      </panel>
-      <panel
-          follows="all"
-          height="68"
-          layout="topleft"
-          left="8"
-          name="camera_modes_list"
-          top="24"
-          width="212"
-          visible="false">
-        <panel_camera_item
-          name="object_view">
-          <panel_camera_item.mousedown_callback
-            function="CameraPresets.ChangeView"
-            parameter="object_view" />
-          <panel_camera_item.text
-            name="object_view_text">
-            Object View
-          </panel_camera_item.text>
-          <panel_camera_item.picture
-            image_name="Object_View_Off" />
-          <panel_camera_item.selected_picture
-            image_name="Object_View_On" />
-        </panel_camera_item>
-        <panel_camera_item
-          name="mouselook_view"
-          layout="topleft">
-          <panel_camera_item.mousedown_callback
-            function="CameraPresets.ChangeView"
-            parameter="mouselook_view" />
-          <panel_camera_item.text
-            name="mouselook_view_text">
-            Mouselook View
-          </panel_camera_item.text>
-          <panel_camera_item.picture
-            image_name="MouseLook_View_Off" />
-          <panel_camera_item.selected_picture
-            image_name="MouseLook_View_On" />
-        </panel_camera_item>
-      </panel>
+     width="220">
          <!--TODO: replace + - images -->
          <panel
             border="false"
             class="camera_zoom_panel"
-            height="114"
+            height="123"
             layout="topleft"
             left="0"
             mouse_opaque="false"
             name="zoom"
-            top="20"
-            width="226">
+            top="0"
+            width="220">
            <joystick_rotate
               follows="top|left"
               height="78"
@@ -157,8 +64,8 @@
               sound_flags="3"
               visible="true"
               tool_tip="Orbit camera around focus"
-              top="20"
-              width="78" />                      
+              top="25"
+              width="78" />
            <button
               follows="top|left"
               height="18"
@@ -169,7 +76,7 @@
               left_pad="14" 
               name="zoom_plus_btn"
               width="18"
-              top="18">
+              top="23">
              <commit_callback
                 function="Zoom.plus" />
              <mouse_held_callback
@@ -214,56 +121,136 @@
          scale_image="false"
          sound_flags="3"
          tool_tip="Move camera up and down, left and right"
-         top="20"
+         top="25"
          width="78"/>
+         <text
+          type="string"
+          length="1"
+          follows="left|top"
+          height="15"
+          layout="topleft"
+          left="41"
+          top_pad="9"
+          name="precise_ctrs_label"
+          width="200">
+            Use precise controls
+        </text>
         </panel>
     </panel>
     <panel
-     border="false"
-     height="42"
+     follows="all"
+     height="102"
      layout="topleft"
-     left="2"
-     top_pad="0"
-     name="buttons"
-     width="226">
-        <button
-         height="23"
-         label=""
-         layout="topleft"
-         left="70"
-         is_toggle="true"
-         image_overlay="Cam_Avatar_Off"
-         image_selected="PushButton_Selected_Press"
-         name="presets_btn"
-         tab_stop="false"
-         tool_tip="Preset Views"
-         top="13" 
-         width="25">
-        </button>
-        <button
-         height="23"
-         label=""
-         layout="topleft"
-         left_pad="1"
-         is_toggle="true"
-         image_overlay="PanOrbit_Off"
-         image_selected="PushButton_Selected_Press"
-         name="pan_btn"
-         tab_stop="false"
-         tool_tip="Orbit Zoom Pan"
-         width="25">
-        </button>
-        <button
-         height="23"
-         label=""
-         layout="topleft"
-         left_pad="1"
-         image_overlay="Cam_FreeCam_Off"
-         image_selected="PushButton_Selected_Press"
-         name="avatarview_btn"
-         tab_stop="false"
-         tool_tip="Camera modes"
-         width="25">
-        </button>
-    </panel>
+     left_pad="2"
+     name="buttons_panel"
+     top="22"
+     width="212">
+    <panel_camera_item
+      name="front_view"
+      tool_tip="Front View"
+      width="30">
+      <panel_camera_item.mousedown_callback
+        function="CameraPresets.ChangeView"
+        parameter="Front View" />
+      <panel_camera_item.picture
+        image_name="Cam_Preset_Front_Off" />
+      <panel_camera_item.selected_picture
+        image_name="Cam_Preset_Front_On" />
+    </panel_camera_item>
+    <panel_camera_item
+      name="group_view"
+      tool_tip="Side View"
+      width="30"
+      left_pad="4">
+      <panel_camera_item.mousedown_callback
+        function="CameraPresets.ChangeView"
+        parameter="Side View" />
+      <panel_camera_item.picture
+        image_name="Cam_Preset_Side_Off" />
+      <panel_camera_item.selected_picture
+        image_name="Cam_Preset_Side_On" />
+    </panel_camera_item>
+    <panel_camera_item
+      name="rear_view"
+      tool_tip="Rear View"
+      width="30"
+      left_pad="4">
+      <panel_camera_item.mousedown_callback
+        function="CameraPresets.ChangeView"
+        tool_tip="Rear View"
+        parameter="Rear View" />
+      <panel_camera_item.picture
+        image_name="Cam_Preset_Back_Off" />
+      <panel_camera_item.selected_picture
+        image_name="Cam_Preset_Back_On" />
+    </panel_camera_item>
+    <panel_camera_item
+        name="object_view"
+        tool_tip="Object View"
+        width="30"
+        left_pad="4">
+        <panel_camera_item.mousedown_callback
+          function="CameraPresets.ChangeView"
+          parameter="object_view" />
+        <panel_camera_item.picture
+          image_name="Object_View_Off" />
+        <panel_camera_item.selected_picture
+          image_name="Object_View_On" />
+      </panel_camera_item>
+      <panel_camera_item
+        name="mouselook_view"
+        tool_tip="Mouselook View"
+        width="30"
+        left_pad="4">
+        <panel_camera_item.mousedown_callback
+          function="CameraPresets.ChangeView"
+          parameter="mouselook_view" />
+        <panel_camera_item.picture
+          image_name="MouseLook_View_Off" />
+        <panel_camera_item.selected_picture
+          image_name="MouseLook_View_On" />
+      </panel_camera_item>
+      <combo_box
+        height="23"
+        left="0"
+        mouse_opaque="true"
+        name="preset_combo"
+        top_pad="10"
+        width="136">
+        <combo_list
+        mouse_wheel_opaque="true"/>
+        <combo_box.item
+         label="Use preset"
+         name="Use preset"
+         value="default" />
+      </combo_box>
+      <button
+        height="16"
+        width="16"  
+        layout="topleft"
+        mouse_opaque="true"
+        name="gear_btn"
+        tool_tip="My Camera Presets"
+        top_delta="3"
+        left_pad="10" 
+        image_selected="Icon_Gear"
+        image_pressed="Icon_Gear"
+        image_unselected="Icon_Gear"
+        is_toggle="true">
+        <button.commit_callback
+          function="CameraPresets.ShowPresetsList"/>
+      </button>
+      <button
+        follows="top|left"
+        height="25"
+        label="Save as preset..."
+        layout="topleft"
+        left="0"
+        name="save_preset_btn"
+        top_pad="18"
+        width="150">
+        <button.commit_callback
+          function="CameraPresets.Save"/>
+      </button>
+  </panel>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_camera_presets.xml b/indra/newview/skins/default/xui/en/floater_camera_presets.xml
new file mode 100644
index 0000000000000000000000000000000000000000..930357f5688d88ced839975a44beeb0f9a0e0deb
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_camera_presets.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ height="200"
+ min_height="150"
+ title="MY CAMERA PRESETS"
+ layout="topleft"
+ name="floater_camera_presets"
+ single_instance="true"
+ min_width="185"
+ width="250">
+  <flat_list_view
+    allow_select="true"
+    follows="all"
+    height="165"
+    layout="topleft"
+    left="3"
+    multi_select="false"
+    name="preset_list"
+    top="20"
+    width="245" />
+  </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_delete_pref_preset.xml b/indra/newview/skins/default/xui/en/floater_delete_pref_preset.xml
index 0688fdb42c2f8d23079d3704c8aa9d7a80f50728..3360d7bec9766fd3868ea01850a6c7dd1fd1ce41 100644
--- a/indra/newview/skins/default/xui/en/floater_delete_pref_preset.xml
+++ b/indra/newview/skins/default/xui/en/floater_delete_pref_preset.xml
@@ -4,7 +4,7 @@
  height="130"
  help_topic="floater_delete_preset"
  layout="topleft"
- name="Delete Pref Preset"
+ name="delete_pref_preset"
  save_rect="true"
  title="DELETE PREF PRESET"
  width="300">
diff --git a/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml b/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml
index 52084e5f8ed07390d63097c4578346513c01fffb..3570456b444eed0b368135e2fc9707d94572378f 100644
--- a/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml
+++ b/indra/newview/skins/default/xui/en/floater_edit_hover_height.xml
@@ -4,18 +4,16 @@
  legacy_header_height="225"
  can_minimize="true"
  can_close="true"
- can_resize="true"
- min_height="65"
- min_width="515"
- height="65"
+ can_resize="false"
+ height="80"
+ width="515"
  layout="topleft"
  name="HoverHeight"
  single_instance="true"
  help_topic="hover_height"
  save_rect="true"
  save_visibility="true"
- title="SET HOVER HEIGHT"
- width="515">
+ title="SET HOVER HEIGHT">
       <slider
      enabled="false"
      control_name="HoverHeightSlider"
@@ -34,4 +32,13 @@
      can_edit_text="true"
      >
     </slider>
+  <check_box
+     control_name="HoverHeightAffectsCamera"
+     follows="all"
+     height="15"
+     label="Bind Camera view"
+     layout="topleft"
+     name="BindCameraCheck"
+     top_pad="7"
+     width="237"/>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_load_pref_preset.xml b/indra/newview/skins/default/xui/en/floater_load_pref_preset.xml
index 5f2eb770e25a4670f3e59b16fad27e11c47093d7..49c21f1ea794d2e3bbb9f25b15a2f2f44351932e 100644
--- a/indra/newview/skins/default/xui/en/floater_load_pref_preset.xml
+++ b/indra/newview/skins/default/xui/en/floater_load_pref_preset.xml
@@ -4,7 +4,7 @@
  height="130"
  help_topic="floater_load_preset"
  layout="topleft"
- name="Load Pref Preset"
+ name="load_pref_preset"
  save_rect="true"
  title="LOAD PREF PRESET"
  width="300">
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_view_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_view_advanced.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4c3c7e49300f0bdb0b28f46c2aceb80bd018d59d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_preferences_view_advanced.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ height="190"
+ layout="topleft"
+ name="floaterpreferencesviewadvanced"
+ help_topic="floaterviewadvanced"
+ title="CAMERA POSITION"
+ save_rect="true"
+ width="280">
+
+  <text
+    follows="top|left|right"
+    name="camera_offset_lbl"
+    height="16"
+    layout="topleft"
+    left="10"
+    top="10"
+    width="100">
+      Camera offset:
+  </text>
+
+  <spinner
+   height="20"
+   label="X"
+   label_width="12"
+   follows="top|left"
+   left="10"
+   name="camera_x"
+   top_pad="5"
+   min_val="-1e+007"
+   max_val="1e+007"
+   width="70">
+    <spinner.commit_callback
+     function="CommitSettings" />
+  </spinner>
+
+  <spinner
+   height="20"
+   label="Y"
+   label_width="12"
+   follows="top|left"
+   name="camera_y"
+   left_pad="20"
+   min_val="-1e+007"
+   max_val="1e+007"
+   width="70">
+    <spinner.commit_callback
+     function="CommitSettings" />
+  </spinner>
+
+  <spinner
+   height="20"
+   label="Z"
+   label_width="12"
+   follows="top|left"
+   name="camera_z"
+   left_pad="20"
+   min_val="-1e+007"
+   max_val="1e+007"
+   width="70">
+    <spinner.commit_callback
+     function="CommitSettings" />
+  </spinner>
+
+  <text
+    follows="top|left|right"
+    name="focus_offset_lbl"
+    height="16"
+    layout="topleft"
+    left="10"
+    top_pad="20"
+    width="100">
+      Focus offset:
+  </text>
+
+  <spinner
+   height="20"
+   label="X"
+   label_width="12"
+   follows="top|left"
+   left="10"
+   name="focus_x"
+   top_pad="5"
+   min_val="-1e+007"
+   max_val="1e+007"
+   width="70">
+    <spinner.commit_callback
+     function="CommitSettings" />
+  </spinner>
+
+  <spinner
+   height="20"
+   label="Y"
+   label_width="12"
+   follows="top|left"
+   name="focus_y"
+   left_pad="20"
+   min_val="-1e+007"
+   max_val="1e+007"
+   width="70">
+    <spinner.commit_callback
+     function="CommitSettings" />
+  </spinner>
+
+  <spinner
+   height="20"
+   label="Z"
+   label_width="12"
+   follows="top|left"
+   name="focus_z"
+   left_pad="20"
+   min_val="-1e+007"
+   max_val="1e+007"
+   width="70">
+    <spinner.commit_callback
+     function="CommitSettings" />
+  </spinner>
+
+   <text
+    follows="top|left|right"
+    name="offset_scale_lbl"
+    height="16"
+    layout="topleft"
+    left="10"
+    top_pad="20"
+    width="140">
+      Camera offset scale:
+  </text>
+
+  <slider
+   control_name="CameraOffsetScale"
+   follows="top|left|right"
+   height="16"
+   top_pad="5"
+   increment="0.1"
+   min_val="-3"
+   max_val="5"
+   show_text="false"
+   layout="topleft"
+   left="3"
+   name="offset_scale_sld"
+   width="196" />
+  <spinner
+   control_name="CameraOffsetScale"
+   height="20"
+   follows="top|left|right"
+   left_pad="5"
+   name="offset_scale_ctrl"
+   min_val="-3"
+   max_val="5"
+   width="58">
+    <spinner.commit_callback
+     function="CommitSettings" />
+  </spinner>
+
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_save_camera_preset.xml b/indra/newview/skins/default/xui/en/floater_save_camera_preset.xml
new file mode 100644
index 0000000000000000000000000000000000000000..54fdb6d1670810eefa4628e383a6eb33073e99a1
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_save_camera_preset.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<floater
+ legacy_header_height="18"
+ height="185"
+ help_topic="floater_save_preset"
+ layout="topleft"
+ name="save_camera_preset"
+ save_rect="true"
+ title="Save Camera Preset"
+ width="280">
+
+    <string name="btn_label_save">Save</string>
+    <string name="btn_label_replace">Replace</string>
+    <radio_group
+     height="85"
+     layout="topleft"
+     left="20"
+     top="15"
+     width="150"
+     name="radio_save_preset">
+     <radio_item
+      label="Save as a new preset"
+      name="new_preset"
+      top="10" 
+      layout="topleft"
+      height="16" 
+      value="0"/>
+     <radio_item
+      label="Replace a preset"
+      name="replace_preset"
+      layout="topleft"
+      top="70" 
+      height="16" 
+      value="1"/>
+    </radio_group> 
+    <line_editor
+     commit_on_focus_lost = "true"
+     follows="top|left"
+     height="23"
+     layout="topleft"
+     left="41"
+     name="preset_txt_editor"
+     width="200"
+     top="45"/>
+    <button
+     follows="top|left"
+     height="25"
+     label="Save"
+     layout="topleft"
+     top="145"
+     left="25"
+     name="save"
+     width="110"/>
+    <button
+     follows="bottom|right"
+     height="25"
+     label="Cancel"
+     layout="topleft"
+     left_pad="20"
+     name="cancel"
+     width="110"/>
+<!-- *HACK to correctly draw drop-down list over the buttons-->
+    <combo_box
+     follows="top|left"
+     layout="topleft"
+     left="41"
+     name="preset_combo"
+     top_delta="-40"
+     width="200"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_save_pref_preset.xml b/indra/newview/skins/default/xui/en/floater_save_pref_preset.xml
index 7dee28eff3a1d5111c3e685e1730ee1435f906ee..62260274f5cfca9e4dd4edc067ae02443952bdfd 100644
--- a/indra/newview/skins/default/xui/en/floater_save_pref_preset.xml
+++ b/indra/newview/skins/default/xui/en/floater_save_pref_preset.xml
@@ -4,14 +4,11 @@
  height="145"
  help_topic="floater_save_preset"
  layout="topleft"
- name="Save Pref Preset"
+ name="save_pref_preset"
  save_rect="true"
- title="SAVE PREF PRESET"
+ title="Save Graphic Preset"
  width="300">
 
-    <string name="title_graphic">Save Graphic Preset</string>
-    <string name="title_camera">Save Camera Preset</string>
-
     <text
      follows="top|left|right"
      height="32"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 089498dfb98959b49bb16be4e1e3990381d6be27..8a91a1f721844c537d59820835926b4005d10131 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -8533,6 +8533,18 @@ Error saving preset [NAME].
 Can not overwrite default preset.
   </notification>
 
+  <notification
+    icon="alertmodal.tga"
+    name="PresetAlreadyExists"
+    type="alertmodal">
+&apos;[NAME]&apos; is in use. You may replace
+this preset or choose another name.
+    <tag>fail</tag>
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+
   <notification
     icon="notifytip.tga"
     name="PresetNotDeleted"
diff --git a/indra/newview/skins/default/xui/en/panel_camera_preset_item.xml b/indra/newview/skins/default/xui/en/panel_camera_preset_item.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9417ab4ac2d0de1b36cf36e69b6550bad7dbd1cb
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_camera_preset_item.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="20"
+ layout="topleft"
+ left="0"
+ name="camera_preset_item"
+ top="0"
+ width="280">
+    <icon
+     follows="top|right|left"
+     height="20"
+     image_name="ListItem_Over"
+     layout="topleft"
+     left="0"
+     name="hovered_icon"
+     top="0"
+     visible="false"
+     width="380" />
+    <icon
+     height="20"
+     follows="top|right|left"
+     image_name="ListItem_Select"
+     layout="topleft"
+     left="0"
+     name="selected_icon"
+     top="0"
+     visible="false"
+     width="380" />
+    <text
+     follows="left"
+     height="20"
+     layout="topleft"
+     left="10"
+     parse_urls="false"
+     use_ellipses="true"
+     name="preset_name"
+     text_color="White"
+     top="2"
+     value="Default"
+     width="159" />
+    <button
+     follows="right"
+     image_selected="TrashItem_Off"
+     image_pressed="TrashItem_Off"
+     image_unselected="TrashItem_Off"
+     is_toggle="true"
+     layout="topleft"
+     left_pad="5"
+     right="-10"
+     name="delete_btn"
+     tool_tip="Delete preset"
+     top="3"
+     height="18"
+     width="18" >
+      <button.commit_callback
+        function="CameraPresets.Delete"/>
+    </button>
+  <button
+   follows="right"
+   image_selected="Refresh_Off"
+   image_pressed="Refresh_Off"
+   image_unselected="Refresh_Off"
+   is_toggle="true"
+   layout="topleft"
+   left_pad="5"
+   right="-10"
+   name="reset_btn"
+   tool_tip="Reset preset to default"
+   top="2"
+   height="20"
+   width="20" >
+    <button.commit_callback
+      function="CameraPresets.Reset"/>
+  </button>
+</panel>
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 4d9152e9a5174094d690e7a42c02aa9b498a22ec..5aff7a512768ab1d69fdf897df8f5c6958598d0b 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -293,6 +293,21 @@
     width="65">
        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="AlwaysRenderFriends"
     height="16"
@@ -345,7 +360,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_presets_camera_pulldown.xml b/indra/newview/skins/default/xui/en/panel_presets_camera_pulldown.xml
new file mode 100644
index 0000000000000000000000000000000000000000..25d9c47449fac1ba042d2b7c32f3b8029a7b0fa8
--- /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 Camera floater"
+    tool_tip = "Bring up Camera floater"
+    top_delta="5"
+    left="15"
+    height="20"
+    width="200">
+    <button.commit_callback
+      function="Presets.toggleCameraFloater" />
+  </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 52bcce01f7d7311471b2d1e3a1a7bf3ce975116d..ada980cda19616fcf60d14e6635fca3b0dc5df3f 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -75,7 +75,7 @@
   </panel>
   <panel
     height="18"
-    left="-416"
+    left="-458"
     width="185"
     top="1"
     follows="right|top" 
@@ -148,11 +148,19 @@
     <icon
      follows="right|top"
      height="16"
-     image_name="Presets_Icon"
+     image_name="Cam_FreeCam_Off"
      left_pad="8"
      top="2"
-     name="presets_icon"
+     name="presets_icon_camera"
      width="18" />
+    <icon
+     follows="right|top"
+     height="13"
+     image_name="Presets_Icon"
+     left_pad="8"
+     top="4"
+     name="presets_icon_graphic"
+     width="16" />
     <button
      follows="right|top"
      height="16"
diff --git a/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
index 98707b84957005e3148e88319b2dcdb3ef7886d4..564f695cd05c2804a5d7cdbe35bb05fea9b1168e 100644
--- a/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
+++ b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
@@ -15,7 +15,7 @@
      top="30"
      scale_image="true"
      visible="false"
-     width="212" />
+     width="30" />
   <panel_camera_item.icon_selected
    follows="top|left"
      height="30"
@@ -27,7 +27,7 @@
      top="30"
      scale_image="true"
      visible="false"
-     width="212" />
+     width="30" />
   <panel_camera_item.picture
      follows="top|left"
      height="30"
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 59929c198bb206891099e558dead260f952316a0..ffc071e70b3f2983619cc4bc6f4eb42920bc7c81 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -78,6 +78,9 @@ def construct(self):
                 contributor_names = self.extract_names(contributions_path)
                 self.put_in_file(contributor_names, "contributors.txt", src=contributions_path)
 
+                # ... and the default camera position settings
+                self.path("camera")
+
                 # ... and the entire windlight directory
                 self.path("windlight")