From c75d443c8359f0bceee2df2adc0a67b2890922ea Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Mon, 4 Nov 2019 20:35:34 +0200
Subject: [PATCH] SL-12186 WIP Updating UI for camera controls, including
 presets

---
 indra/newview/app_settings/camera/Front.xml   |   8 +-
 .../app_settings/camera/Pennys_Gamer.xml      | 115 -------
 indra/newview/app_settings/camera/Side.xml    |   8 +-
 indra/newview/app_settings/settings.xml       |  30 ++
 indra/newview/llagentcamera.cpp               |  17 +
 indra/newview/llagentcamera.h                 |   9 +-
 indra/newview/llfloatercamera.cpp             | 118 +++----
 indra/newview/llfloatercamera.h               |  10 +-
 .../llfloaterpreferenceviewadvanced.cpp       |  40 +--
 .../newview/llfloaterpreferenceviewadvanced.h |   7 -
 indra/newview/llfloatersaveprefpreset.cpp     |  80 ++++-
 indra/newview/llfloatersaveprefpreset.h       |   9 +-
 indra/newview/llpresetsmanager.cpp            |  96 +++---
 indra/newview/llpresetsmanager.h              |   4 +
 .../skins/default/xui/en/floater_camera.xml   | 292 ++++++++----------
 .../en/floater_preferences_view_advanced.xml  |  28 +-
 .../xui/en/floater_save_pref_preset.xml       |  60 ++--
 .../skins/default/xui/en/notifications.xml    |  12 +
 .../xui/en/widgets/panel_camera_item.xml      |   4 +-
 19 files changed, 443 insertions(+), 504 deletions(-)
 delete mode 100644 indra/newview/app_settings/camera/Pennys_Gamer.xml

diff --git a/indra/newview/app_settings/camera/Front.xml b/indra/newview/app_settings/camera/Front.xml
index d5ead526b7d..a4b5ace33c6 100644
--- a/indra/newview/app_settings/camera/Front.xml
+++ b/indra/newview/app_settings/camera/Front.xml
@@ -37,10 +37,10 @@
                 <real>6</real>
             </array>
         </map>
-    <key>CameraOffsetRearView</key>
+    <key>CameraOffsetFrontView</key>
         <map>
         <key>Comment</key>
-            <string>Initial camera offset from avatar in Rear View</string>
+            <string>Initial camera offset from avatar in Front View</string>
         <key>Persist</key>
             <integer>1</integer>
         <key>Type</key>
@@ -74,10 +74,10 @@
         <key>Value</key>
             <integer>0</integer>
         </map>
-    <key>FocusOffsetRearView</key>
+    <key>FocusOffsetFrontView</key>
         <map>
         <key>Comment</key>
-            <string>Initial focus point offset relative to avatar for the camera preset Rear View (x-axis is forward)</string>
+            <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>
diff --git a/indra/newview/app_settings/camera/Pennys_Gamer.xml b/indra/newview/app_settings/camera/Pennys_Gamer.xml
deleted file mode 100644
index 5d249153a02..00000000000
--- a/indra/newview/app_settings/camera/Pennys_Gamer.xml
+++ /dev/null
@@ -1,115 +0,0 @@
-<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>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.0</real>
-                <real>0.0</real>
-                <real>-0.2</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>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>0.9</real>
-                <real>0.0</real>
-                <real>0.2</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
index 4cd5f2f5a4a..677fd47e205 100644
--- a/indra/newview/app_settings/camera/Side.xml
+++ b/indra/newview/app_settings/camera/Side.xml
@@ -37,10 +37,10 @@
                 <real>6</real>
             </array>
         </map>
-    <key>CameraOffsetRearView</key>
+    <key>CameraOffsetGroupView</key>
         <map>
         <key>Comment</key>
-            <string>Initial camera offset from avatar in Rear View</string>
+            <string>Initial camera offset from avatar in Side View</string>
         <key>Persist</key>
             <integer>1</integer>
         <key>Type</key>
@@ -74,10 +74,10 @@
         <key>Value</key>
             <integer>0</integer>
         </map>
-    <key>FocusOffsetRearView</key>
+    <key>FocusOffsetGroupView</key>
         <map>
         <key>Comment</key>
-            <string>Initial focus point offset relative to avatar for the camera preset Rear View (x-axis is forward)</string>
+            <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>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a02cccb6138..f44185340a0 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1499,6 +1499,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>
@@ -4356,6 +4371,21 @@
         <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>FocusPosOnLogout</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index bbe1354fc36..3e56c1dd714 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -210,10 +210,12 @@ void LLAgentCamera::init()
 	mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView");
 	mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView");
 	mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView");
+	mCameraOffsetInitial[CAMERA_PRESET_CUSTOM] = gSavedSettings.getControl("CameraOffsetCustomPreset");
 
 	mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView");
 	mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView");
 	mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView");
+	mFocusOffsetInitial[CAMERA_PRESET_CUSTOM] = gSavedSettings.getControl("FocusOffsetCustomPreset");
 
 	mCameraCollidePlane.clearVec();
 	mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
@@ -1936,6 +1938,21 @@ LLVector3 LLAgentCamera::getCameraOffsetInitial()
 	return convert_from_llsd<LLVector3>(mCameraOffsetInitial[mCameraPreset]->get(), TYPE_VEC3, "");
 }
 
+LLVector3d LLAgentCamera::getFocusOffsetInitial()
+{
+	return convert_from_llsd<LLVector3d>(mFocusOffsetInitial[mCameraPreset]->get(), TYPE_VEC3D, "");
+}
+
+std::string LLAgentCamera::getCameraOffsetCtrlName()
+{
+	return mCameraOffsetInitial[mCameraPreset]->getName();
+}
+
+std::string LLAgentCamera::getFocusOffsetCtrlName()
+{
+	return mFocusOffsetInitial[mCameraPreset]->getName();
+}
+
 F32 LLAgentCamera::getCameraMaxZoomDistance()
 {
     // Ignore "DisableCameraConstraints", we don't want to be out of draw range when we focus onto objects or avatars
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index 4575c1501a7..294e81c2e1a 100644
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -59,7 +59,7 @@ enum ECameraPreset
 	CAMERA_PRESET_GROUP_VIEW,
 
 	/** Current view when a preset is saved */
-	CAMERA_PRESET_CUSTOM0
+	CAMERA_PRESET_CUSTOM
 };
 
 //------------------------------------------------------------------------
@@ -112,9 +112,14 @@ 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();
+
+	std::string getCameraOffsetCtrlName();
+	std::string getFocusOffsetCtrlName();
+private:
 	/** Determines maximum camera distance from target for mouselook, opposite to LAND_MIN_ZOOM */
 	F32 getCameraMaxZoomDistance();
 
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index c12ccb386ed..933e7586533 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"
@@ -53,7 +54,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;
@@ -270,13 +270,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()
@@ -323,6 +317,8 @@ void LLFloaterCamera::onOpen(const LLSD& key)
 	else
 		toPrevMode();
 	mClosed = FALSE;
+
+	populatePresetCombo();
 }
 
 void LLFloaterCamera::onClose(bool app_quitting)
@@ -354,7 +350,7 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val)
 {
 	LLHints::registerHintTarget("view_popup", getHandle());
 	mCommitCallbackRegistrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
-	mCommitCallbackRegistrar.add("Presets.GoViewPrefs", boost::bind(&LLFloaterCamera::onViewButtonClick, this, _2));
+	mCommitCallbackRegistrar.add("CameraPresets.Save", boost::bind(&LLFloaterCamera::onSavePreset, this));
 }
 
 // virtual
@@ -366,9 +362,11 @@ BOOL LLFloaterCamera::postBuild()
 	mZoom = findChild<LLPanelCameraZoom>(ZOOM);
 	mTrack = getChild<LLJoystickCameraTrack>(PAN);
 
-	assignButton2Mode(CAMERA_CTRL_MODE_MODES,			"avatarview_btn");
-	assignButton2Mode(CAMERA_CTRL_MODE_PAN,				"pan_btn");
-	assignButton2Mode(CAMERA_CTRL_MODE_PRESETS,		"presets_btn");
+	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));
+	getChild<LLComboBox>("preset_combo")->setCommitCallback(boost::bind(&LLFloaterCamera::onCustomPresetSelected, this));
+	LLPresetsManager::getInstance()->setPresetListChangeCameraCallback(boost::bind(&LLFloaterCamera::populatePresetCombo, this));
 
 	update();
 
@@ -387,24 +385,6 @@ F32	LLFloaterCamera::getCurrentTransparency()
 
 }
 
-void LLFloaterCamera::onViewButtonClick(const LLSD& user_data)
-{
-	// bring up the prefs floater
-	LLFloater* prefsfloater = LLFloaterReg::showInstance("preferences");
-	if (prefsfloater)
-	{
-		// grab the 'view' panel from the preferences floater and
-		// bring it the front!
-		LLTabContainer* tabcontainer = prefsfloater->getChild<LLTabContainer>("pref core");
-		LLPanel* graphicspanel = prefsfloater->getChild<LLPanel>("view");
-		if (tabcontainer && graphicspanel)
-		{
-			tabcontainer->selectTabPanel(graphicspanel);
-		}
-	}
-}
-
-
 void LLFloaterCamera::fillFlatlistFromPanel (LLFlatListView* list, LLPanel* panel)
 {
 	// copying child list and then iterating over a copy, because list itself
@@ -473,13 +453,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();
@@ -503,36 +476,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)
@@ -552,11 +497,11 @@ void LLFloaterCamera::updateItemsSelection()
 {
 	ECameraPreset preset = (ECameraPreset) gSavedSettings.getU32("CameraPreset");
 	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);
@@ -580,6 +525,9 @@ void LLFloaterCamera::onClickCameraItem(const LLSD& param)
 	}
 	else
 	{
+		LLFloaterCamera* camera_floater = LLFloaterCamera::findInstance();
+		if (camera_floater)
+			camera_floater->switchMode(CAMERA_CTRL_MODE_PAN);
 		switchToPreset(name);
 	}
 
@@ -599,14 +547,17 @@ void LLFloaterCamera::switchToPreset(const std::string& name)
 	if ("rear_view" == name)
 	{
 		gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
+		LLPresetsManager::getInstance()->loadPreset(PRESETS_CAMERA, PRESETS_REAR);
 	}
 	else if ("group_view" == name)
 	{
 		gAgentCamera.switchCameraPreset(CAMERA_PRESET_GROUP_VIEW);
+		LLPresetsManager::getInstance()->loadPreset(PRESETS_CAMERA, PRESETS_SIDE);
 	}
 	else if ("front_view" == name)
 	{
 		gAgentCamera.switchCameraPreset(CAMERA_PRESET_FRONT_VIEW);
+		LLPresetsManager::getInstance()->loadPreset(PRESETS_CAMERA, PRESETS_FRONT);
 	}
 }
 
@@ -617,3 +568,36 @@ void LLFloaterCamera::fromFreeToPresets()
 		switchMode(CAMERA_CTRL_MODE_PRESETS);
 	}
 }
+
+void LLFloaterCamera::populatePresetCombo()
+{
+	LLPresetsManager::getInstance()->setPresetNamesInComboBox(PRESETS_CAMERA, getChild<LLComboBox>("preset_combo"), EDefaultOptions::DEFAULT_VIEWS_HIDE);
+	if ((ECameraPreset)gSavedSettings.getU32("CameraPreset") == CAMERA_PRESET_CUSTOM)
+	{
+		getChild<LLComboBox>("preset_combo")->selectByValue(gSavedSettings.getString("PresetCameraActive"));
+	}
+	else
+	{
+		std::string inactive_text = getString("inactive_combo_text");
+		getChild<LLComboBox>("preset_combo")->setLabel(inactive_text);// add(inactive_text, inactive_text, ADD_TOP);
+	}
+}
+
+void LLFloaterCamera::onSavePreset()
+{
+	LLFloaterReg::hideInstance("delete_pref_preset", PRESETS_CAMERA);
+	LLFloaterReg::hideInstance("load_pref_preset", PRESETS_CAMERA);
+	LLFloaterReg::showInstance("save_pref_preset", PRESETS_CAMERA);
+}
+
+void LLFloaterCamera::onCustomPresetSelected()
+{
+	std::string selected_preset = getChild<LLComboBox>("preset_combo")->getSelectedItemLabel();
+	if (gSavedSettings.getString("PresetCameraActive") != selected_preset && getString("inactive_combo_text") != selected_preset)
+	{
+		gAgentCamera.switchCameraPreset(CAMERA_PRESET_CUSTOM);
+		updateItemsSelection();
+		fromFreeToPresets();
+		LLPresetsManager::getInstance()->loadPreset(PRESETS_CAMERA, selected_preset);
+	}
+}
diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h
index 481e9aec1bb..b1e0c83ce07 100644
--- a/indra/newview/llfloatercamera.h
+++ b/indra/newview/llfloatercamera.h
@@ -39,7 +39,6 @@ class LLPanelCameraZoom;
 
 enum ECameraControlMode
 {
-	CAMERA_CTRL_MODE_MODES,
 	CAMERA_CTRL_MODE_PAN,
 	CAMERA_CTRL_MODE_FREE_CAMERA,
 	CAMERA_CTRL_MODE_PRESETS
@@ -50,7 +49,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 +75,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;
@@ -112,9 +115,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);
 
diff --git a/indra/newview/llfloaterpreferenceviewadvanced.cpp b/indra/newview/llfloaterpreferenceviewadvanced.cpp
index 791ff79d87a..57484d0d0aa 100644
--- a/indra/newview/llfloaterpreferenceviewadvanced.cpp
+++ b/indra/newview/llfloaterpreferenceviewadvanced.cpp
@@ -25,6 +25,7 @@
  */
 
 #include "llviewerprecompiledheaders.h"
+#include "llagentcamera.h"
 #include "llfloaterpreferenceviewadvanced.h"
 #include "llfloater.h"
 #include "llfloaterreg.h"
@@ -36,40 +37,12 @@
 LLFloaterPreferenceViewAdvanced::LLFloaterPreferenceViewAdvanced(const LLSD& key) 
 :	LLFloater(key)
 {
-	mCommitCallbackRegistrar.add("Cancel",	boost::bind(&LLFloaterPreferenceViewAdvanced::onClickCancel, this));
 	mCommitCallbackRegistrar.add("CommitSettings",	boost::bind(&LLFloaterPreferenceViewAdvanced::onCommitSettings, this));
-	mCommitCallbackRegistrar.add("Ok",	boost::bind(&LLFloaterPreferenceViewAdvanced::onClickOk, this));
-
 }
 
 LLFloaterPreferenceViewAdvanced::~LLFloaterPreferenceViewAdvanced()
 {}
 
-void LLFloaterPreferenceViewAdvanced::onClickOk()
-{
-	closeFloater();
-}
-
-void LLFloaterPreferenceViewAdvanced::onClickCancel()
-{
-	gSavedSettings.setVector3("CameraOffsetRearView", mCameraSaved);
-	gSavedSettings.setVector3d("FocusOffsetRearView", mFocusSaved);
-
-	updateCameraControl(mCameraSaved);
-	updateFocusControl(mFocusSaved);
-}
-
-BOOL LLFloaterPreferenceViewAdvanced::postBuild()
-{
-	mCameraSaved = gSavedSettings.getVector3("CameraOffsetRearView");
-	mFocusSaved = gSavedSettings.getVector3d("FocusOffsetRearView");
-
-	updateCameraControl(mCameraSaved);
-	updateFocusControl(mFocusSaved);
-
-	return TRUE;
-}
-
 void LLFloaterPreferenceViewAdvanced::updateCameraControl(const LLVector3& vector)
 {
 	getChild<LLSpinCtrl>("camera_x")->setValue(vector[VX]);
@@ -86,11 +59,8 @@ void LLFloaterPreferenceViewAdvanced::updateFocusControl(const LLVector3d& vecto
 
  void LLFloaterPreferenceViewAdvanced::draw()
 {
-	static LLCachedControl<LLVector3> camera(gSavedSettings, "CameraOffsetRearView");
-	static LLCachedControl<LLVector3d> focus(gSavedSettings, "FocusOffsetRearView");
-
-	updateCameraControl(camera);
-	updateFocusControl(focus);
+	updateCameraControl(gAgentCamera.getCameraOffsetInitial());
+	updateFocusControl(gAgentCamera.getFocusOffsetInitial());
 
 	LLFloater::draw();
 }
@@ -103,10 +73,10 @@ void LLFloaterPreferenceViewAdvanced::onCommitSettings()
 	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);
+	gSavedSettings.setVector3(gAgentCamera.getCameraOffsetCtrlName(), 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);
+	gSavedSettings.setVector3d(gAgentCamera.getFocusOffsetCtrlName(), vector3d);
 }
diff --git a/indra/newview/llfloaterpreferenceviewadvanced.h b/indra/newview/llfloaterpreferenceviewadvanced.h
index 8f4b5946055..4619fdaab16 100644
--- a/indra/newview/llfloaterpreferenceviewadvanced.h
+++ b/indra/newview/llfloaterpreferenceviewadvanced.h
@@ -37,21 +37,14 @@ class LLFloaterPreferenceViewAdvanced
 
 public:
 	LLFloaterPreferenceViewAdvanced(const LLSD& key);
-	virtual BOOL postBuild();
 	virtual void draw();
 
 	void onCommitSettings();
-	void onClickCancel();
-	void onClickOk();
 	void updateCameraControl(const LLVector3& vector);
 	void updateFocusControl(const LLVector3d& vector3d);
 
 private:
 	virtual ~LLFloaterPreferenceViewAdvanced();
-
-	LLVector3	mCameraSaved;
-	LLVector3d	mFocusSaved;
-	
 };
 
 #endif //LLFLOATERPREFERENCEVIEWADVANCED_H
diff --git a/indra/newview/llfloatersaveprefpreset.cpp b/indra/newview/llfloatersaveprefpreset.cpp
index bae76025669..10fad347bf5 100644
--- a/indra/newview/llfloatersaveprefpreset.cpp
+++ b/indra/newview/llfloatersaveprefpreset.cpp
@@ -32,12 +32,14 @@
 #include "llcombobox.h"
 #include "llfloaterpreference.h"
 #include "llfloaterreg.h"
+#include "lllineeditor.h"
 #include "llnotificationsutil.h"
 #include "llpresetsmanager.h"
+#include "llradiogroup.h"
 #include "lltrans.h"
 
 LLFloaterSavePrefPreset::LLFloaterSavePrefPreset(const LLSD &key)
-:	LLFloater(key)
+	: LLModalDialog(key)
 {
 }
 
@@ -49,29 +51,39 @@ BOOL LLFloaterSavePrefPreset::postBuild()
 	{
 		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));
+	
+	mPresetCombo = getChild<LLComboBox>("preset_combo");
+	//mPresetCombo->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetNameEdited, this));
 
-	LLPresetsManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetsListChange, this));
+	mNameEditor = getChild<LLLineEditor>("preset_txt_editor");
+	mNameEditor->setKeystrokeCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetNameEdited, this), NULL);
 
 	mSaveButton = getChild<LLButton>("save");
-	mPresetCombo = getChild<LLComboBox>("preset_combo");
+	mSaveButton->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onBtnSave, this));
+	
+	mSaveRadioGroup = getChild<LLRadioGroup>("radio_save_preset");
+	mSaveRadioGroup->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onSwitchSaveReplace, this));
+	
+	getChild<LLButton>("cancel")->setCommitCallback(boost::bind(&LLFloaterSavePrefPreset::onBtnCancel, this));
+
+	LLPresetsManager::instance().setPresetListChangeCallback(boost::bind(&LLFloaterSavePrefPreset::onPresetsListChange, this));
 
 	return TRUE;
 }
 
 void LLFloaterSavePrefPreset::onPresetNameEdited()
 {
-	// Disable saving a preset having empty name.
-	std::string name = mPresetCombo->getSimple();
-
-	mSaveButton->setEnabled(!name.empty());
+	if (mSaveRadioGroup->getSelectedIndex() == 0)
+	{
+		// Disable saving a preset having empty name.
+		std::string name = mNameEditor->getValue();
+		mSaveButton->setEnabled(!name.empty());
+	}
 }
 
 void LLFloaterSavePrefPreset::onOpen(const LLSD& key)
 {
+	LLModalDialog::onOpen(key);
 	mSubdirectory = key.asString();
 
 	std::string floater_title = getString(std::string("title_") + mSubdirectory);
@@ -81,22 +93,41 @@ void LLFloaterSavePrefPreset::onOpen(const LLSD& key)
 	EDefaultOptions option = DEFAULT_HIDE;
 	LLPresetsManager::getInstance()->setPresetNamesInComboBox(mSubdirectory, mPresetCombo, option);
 
+	mSaveRadioGroup->setSelectedIndex(0);
 	onPresetNameEdited();
+	onSwitchSaveReplace();
 }
 
 void LLFloaterSavePrefPreset::onBtnSave()
 {
-	std::string name = mPresetCombo->getSimple();
+	bool is_saving_new = mSaveRadioGroup->getSelectedIndex() == 0;
+	std::string name = is_saving_new ? mNameEditor->getValue() : mPresetCombo->getSimple();
 
 	if ((name == LLTrans::getString(PRESETS_DEFAULT)) || (name == PRESETS_DEFAULT))
 	{
 		LLNotificationsUtil::add("DefaultPresetNotSaved");
 	}
-	else if (!LLPresetsManager::getInstance()->savePreset(mSubdirectory, name))
+	else 
 	{
-		LLSD args;
-		args["NAME"] = name;
-		LLNotificationsUtil::add("PresetNotSaved", args);
+		if (is_saving_new)
+		{
+			std::list<std::string> preset_names;
+			std::string presets_dir = LLPresetsManager::getInstance()->getPresetsDir(mSubdirectory);
+			LLPresetsManager::getInstance()->loadPresetNamesFromDir(presets_dir, 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(mSubdirectory, name))
+		{
+			LLSD args;
+			args["NAME"] = name;
+			LLNotificationsUtil::add("PresetNotSaved", args);
+		}
 	}
 
 	closeFloater();
@@ -112,3 +143,20 @@ void LLFloaterSavePrefPreset::onBtnCancel()
 {
 	closeFloater();
 }
+
+void LLFloaterSavePrefPreset::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/llfloatersaveprefpreset.h b/indra/newview/llfloatersaveprefpreset.h
index 09a87b8c629..c61379e5ad1 100644
--- a/indra/newview/llfloatersaveprefpreset.h
+++ b/indra/newview/llfloatersaveprefpreset.h
@@ -28,11 +28,13 @@
 #ifndef LL_LLFLOATERSAVEPREFPRESET_H
 #define LL_LLFLOATERSAVEPREFPRESET_H
 
-#include "llfloater.h"
+#include "llmodaldialog.h"
 
 class LLComboBox;
+class LLRadioGroup;
+class LLLineEditor;
 
-class LLFloaterSavePrefPreset : public LLFloater
+class LLFloaterSavePrefPreset : public LLModalDialog
 {
 
 public:
@@ -43,8 +45,11 @@ class LLFloaterSavePrefPreset : public LLFloater
 
 	void onBtnSave();
 	void onBtnCancel();
+	void onSwitchSaveReplace();
 
 private:
+	LLRadioGroup*	mSaveRadioGroup;
+	LLLineEditor*	mNameEditor;
 	LLComboBox*		mPresetCombo;
 	LLButton*		mSaveButton;
 
diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp
index 17fefbe6b13..94e6e647540 100644
--- a/indra/newview/llpresetsmanager.cpp
+++ b/indra/newview/llpresetsmanager.cpp
@@ -65,22 +65,22 @@ void LLPresetsManager::createMissingDefault(const std::string& subdirectory)
 {
 	if(gDirUtilp->getLindenUserDir().empty())
 	{
-		return;
+return;
 	}
 
 	std::string default_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR,
-															  subdirectory, PRESETS_DEFAULT + ".xml");
+		subdirectory, PRESETS_DEFAULT + ".xml");
 	if (!gDirUtilp->fileExists(default_file))
 	{
 		LL_INFOS() << "No default preset found -- creating one at " << default_file << LL_ENDL;
 
 		// Write current settings as the default
-        savePreset(subdirectory, PRESETS_DEFAULT, true);
+		savePreset(subdirectory, PRESETS_DEFAULT, true);
+	}
+	else
+	{
+		LL_DEBUGS() << "default preset exists; no-op" << LL_ENDL;
 	}
-    else
-    {
-        LL_DEBUGS() << "default preset exists; no-op" << LL_ENDL;
-    }
 }
 
 void LLPresetsManager::startWatching(const std::string& subdirectory)
@@ -99,7 +99,7 @@ void LLPresetsManager::startWatching(const std::string& subdirectory)
 				if (cntrl_ptr.isNull())
 				{
 					LL_WARNS("Init") << "Unable to set signal on global setting '" << ctrl_name
-									<< "'" << LL_ENDL;
+						<< "'" << LL_ENDL;
 				}
 				else
 				{
@@ -120,25 +120,25 @@ std::string LLPresetsManager::getPresetsDir(const std::string& subdirectory)
 	if (!gDirUtilp->fileExists(dest_path))
 		LLFile::mkdir(dest_path);
 
-		if (PRESETS_CAMERA == subdirectory)
+	if (PRESETS_CAMERA == subdirectory)
+	{
+		std::string source_dir = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, PRESETS_CAMERA);
+		LLDirIterator dir_iter(source_dir, "*.xml");
+		bool found = true;
+		while (found)
 		{
-			std::string source_dir = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, PRESETS_CAMERA);
-			LLDirIterator dir_iter(source_dir, "*.xml");
-			bool found = true;
-			while (found)
-			{
-				std::string file;
-				found = dir_iter.next(file);
+			std::string file;
+			found = dir_iter.next(file);
 
-				if (found)
-				{
-					std::string source = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, PRESETS_CAMERA, file);
-					file = LLURI::escape(file);
-					std::string dest = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, PRESETS_CAMERA, file);
-					LLFile::copy(source, dest);
-				}
+			if (found)
+			{
+				std::string source = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, PRESETS_CAMERA, file);
+				file = LLURI::escape(file);
+				std::string dest = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PRESETS_DIR, PRESETS_CAMERA, file);
+				LLFile::copy(source, dest);
 			}
 		}
+	}
 
 	return dest_path;
 }
@@ -160,8 +160,15 @@ 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 (default_option == DEFAULT_VIEWS_HIDE)
+			{
+				if (name == PRESETS_REAR || name == PRESETS_SIDE || name == PRESETS_FRONT)
+				{
+					continue;
+				}
+			}
 			if (PRESETS_DEFAULT != name)
 			{
 				mPresetNames.push_back(name);
@@ -205,11 +212,15 @@ void LLPresetsManager::settingChanged()
 {
 	setCameraDirty(true);
 
-	gSavedSettings.setString("PresetCameraActive", "");
-
-// Hack call because this is a static routine
-	LLPresetsManager::getInstance()->triggerChangeCameraSignal();
+	static LLCachedControl<std::string> preset_camera_active(gSavedSettings, "PresetCameraActive", "");
+	std::string preset_name = preset_camera_active;
+	if (!preset_name.empty())
+	{
+		gSavedSettings.setString("PresetCameraActive", "");
 
+		// Hack call because this is a static routine
+		LLPresetsManager::getInstance()->triggerChangeCameraSignal();
+	}
 }
 
 void LLPresetsManager::getControlNames(std::vector<std::string>& names)
@@ -222,8 +233,6 @@ void LLPresetsManager::getControlNames(std::vector<std::string>& names)
 		("AppearanceCameraMovement")
 		// From llagentcamera.cpp
 		("CameraOffsetBuild")
-		("CameraOffsetRearView")
-		("FocusOffsetRearView")
 		("CameraOffsetScale")
 		("TrackFocusObject")
         ;
@@ -286,9 +295,25 @@ bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string n
 	}
 	else
 	{
+		bool custom_camera_offsets = false;
+		if (subdirectory == PRESETS_CAMERA)
+		{
+			name_list.push_back(gAgentCamera.getCameraOffsetCtrlName());
+			name_list.push_back(gAgentCamera.getFocusOffsetCtrlName());
+			custom_camera_offsets = (name != PRESETS_REAR && name != PRESETS_SIDE && name != PRESETS_FRONT);
+		}
 		for (std::vector<std::string>::iterator it = name_list.begin(); it != name_list.end(); ++it)
 		{
 			std::string ctrl_name = *it;
+			std::string dest_ctrl_name = ctrl_name;
+			if (custom_camera_offsets && ctrl_name == gAgentCamera.getCameraOffsetCtrlName())
+			{
+				dest_ctrl_name = "CameraOffsetCustomPreset";
+			}
+			if (custom_camera_offsets && ctrl_name == gAgentCamera.getFocusOffsetCtrlName())
+			{
+				dest_ctrl_name = "FocusOffsetCustomPreset";
+			}
 			LLControlVariable* ctrl = gSavedSettings.getControl(ctrl_name).get();
 			if (ctrl)
 			{
@@ -296,10 +321,10 @@ bool LLPresetsManager::savePreset(const std::string& subdirectory, std::string n
 				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;
+				paramsData[dest_ctrl_name]["Comment"] = comment;
+				paramsData[dest_ctrl_name]["Persist"] = 1;
+				paramsData[dest_ctrl_name]["Type"] = type;
+				paramsData[dest_ctrl_name]["Value"] = value;
 			}
 		}
 	}
@@ -354,6 +379,7 @@ bool LLPresetsManager::setPresetNamesInComboBox(const std::string& subdirectory,
 
 	combo->clearRows();
 
+
 	std::string presets_dir = getPresetsDir(subdirectory);
 
 	if (!presets_dir.empty())
@@ -368,7 +394,7 @@ bool LLPresetsManager::setPresetNamesInComboBox(const std::string& subdirectory,
 			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));
+				combo->add(name, name);
 			}
 		}
 		else
diff --git a/indra/newview/llpresetsmanager.h b/indra/newview/llpresetsmanager.h
index 7370e0a3b1a..cb32b58fc4f 100644
--- a/indra/newview/llpresetsmanager.h
+++ b/indra/newview/llpresetsmanager.h
@@ -36,11 +36,15 @@ 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";
 
 enum EDefaultOptions
 {
 	DEFAULT_SHOW,
 	DEFAULT_TOP,
+	DEFAULT_VIEWS_HIDE,
 	DEFAULT_HIDE				// Do not display "Default" in a list
 };
 
diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml
index 25db24da2ed..933d50acaec 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,130 +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="0"
-            width="226">
-         <slider
-            can_edit_text="true"
-            control_name="CameraAngle"
-            decimal_digits="2"
-            follows="left|top"
-            height="16"
-            top="20"
-            increment="0.025"
-            initial_value="1.57"
-            layout="topleft"
-            label_width="112"
-            label="View angle"
-            left="10"
-            max_val="1.6"
-            min_val="0.17"
-            name="camera_fov"
-            show_text="false"
-            width="200" />
+            width="220">
            <joystick_rotate
               follows="top|left"
               height="78"
@@ -175,8 +64,8 @@
               sound_flags="3"
               visible="true"
               tool_tip="Orbit camera around focus"
-              top_delta="20"
-              width="78" />                      
+              top="25"
+              width="78" />
            <button
               follows="top|left"
               height="18"
@@ -187,7 +76,7 @@
               left_pad="14" 
               name="zoom_plus_btn"
               width="18"
-              top="38">
+              top="23">
              <commit_callback
                 function="Zoom.plus" />
              <mouse_held_callback
@@ -232,53 +121,128 @@
          scale_image="false"
          sound_flags="3"
          tool_tip="Move camera up and down, left and right"
-         top="40"
+         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
-         name="open_prefs_btn"
-         image_overlay="Icon_Gear_Foreground"
-         tool_tip = "Open view preferences"
-         layout="topleft"
-         left="70"
-         height="23"
-         width="28">
-           <button.commit_callback
-             function="Presets.GoViewPrefs" />
-        </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="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>
+    <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_box.item
+         label="Use preset"
+         name="Use preset"
+         value="default" />
+      </combo_box>
+      <icon
+        height="28"
+        width="28"
+        image_name="Command_Preferences_Icon"
+        layout="topleft"
+        mouse_opaque="true"
+        name="icon_gear"
+        tool_tip="My Camera Presets"
+        top_delta="0"
+        left_pad="5" />
+      <button
+        follows="top|left"
+        height="25"
+        label="Save as preset..."
+        layout="topleft"
+        left="0"
+        name="save_preset_btn"
+        top_pad="8"
+        width="150">
+        <button.commit_callback
+          function="CameraPresets.Save"/>
+      </button>
+  </panel>
 </floater>
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
index 5b2cbee9143..3826ead5c2b 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_view_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_view_advanced.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
- height="170"
+ height="128"
  layout="topleft"
  name="floaterpreferencesviewadvanced"
  help_topic="floaterviewadvanced"
- title="ADJUST CAMERA VIEW"
+ title="CAMERA POSITION"
  save_rect="true"
  width="280">
 
@@ -113,28 +113,4 @@
     <spinner.commit_callback
      function="CommitSettings" />
   </spinner>
-
-  <button
-   follows="left|top"
-   height="23"
-   label="OK"
-   layout="topleft"
-   left="90"
-   name="ok"
-   top_pad="30"
-   width="90">
-    <button.commit_callback
-     function="Ok"/>
-  </button>
-  <button
-   follows="left|top"
-   height="23"
-   label="Cancel"
-   layout="topleft"
-   left_pad="5"
-   name="cancel"
-   width="90">
-    <button.commit_callback
-     function="Cancel"/>
-  </button>
 </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 a9cda26f0b0..178ecad0f31 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
@@ -1,51 +1,71 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <floater
  legacy_header_height="18"
- height="145"
+ height="185"
  help_topic="floater_save_preset"
  layout="topleft"
  name="save_pref_preset"
  save_rect="true"
  title="SAVE PREF PRESET"
- width="300">
+ width="280">
 
     <string name="title_graphic">Save Graphic Preset</string>
     <string name="title_camera">Save Camera Preset</string>
-
-    <text
-     follows="top|left|right"
-     height="32"
+    <string name="btn_label_save">Save</string>
+    <string name="btn_label_replace">Replace</string>
+    <radio_group
+     height="85"
      layout="topleft"
-     word_wrap="true"
      left="20"
-     name="Preset"
-     top="30"
-     width="200">
-     Type a name for the preset or choose an existing preset.
-    </text>
+     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"/>
     <combo_box
      follows="top|left"
      layout="topleft"
-     left="20"
+     left="41"
      name="preset_combo"
-     top_delta="35"
-     allow_text_entry="true"
+     top_pad="35"
      width="200"/>
     <button
      follows="top|left"
-     height="23"
+     height="25"
      label="Save"
      layout="topleft"
      top_delta="40"
-     left="20"
+     left="25"
      name="save"
-     width="70"/>
+     width="110"/>
     <button
      follows="bottom|right"
-     height="23"
+     height="25"
      label="Cancel"
      layout="topleft"
      left_pad="20"
      name="cancel"
-     width="70"/>
+     width="110"/>
 </floater>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f72767ccebe..7e06389bfea 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -8355,6 +8355,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/widgets/panel_camera_item.xml b/indra/newview/skins/default/xui/en/widgets/panel_camera_item.xml
index 98707b84957..564f695cd05 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"
-- 
GitLab