diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 9282196b86d7d7add999226e162fad69cd9887d1..182341685be16c06204c6f783f532a3c819cbbde 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -52,6 +52,7 @@
 #include "llfavoritesbar.h"
 #include "llfloatersidepanelcontainer.h"
 #include "llfloaterimsession.h"
+#include "llkeybindings.h"
 #include "llkeyboard.h"
 #include "llmodaldialog.h"
 #include "llnavigationbar.h"
@@ -168,6 +169,7 @@ class LLVoiceSetKeyDialog : public LLModalDialog
 	/*virtual*/ BOOL postBuild();
 	
 	void setParent(LLFloaterPreference* parent) { mParent = parent; }
+	void setTmpParent(LLPanelPreferenceControls* parent) { mTmpParent = parent; } // todo: voice key will be removed, class renamved, so it will have only one parent
 	
 	BOOL handleKeyHere(KEY key, MASK mask);
 	BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
@@ -175,11 +177,13 @@ class LLVoiceSetKeyDialog : public LLModalDialog
 		
 private:
 	LLFloaterPreference* mParent;
+	LLPanelPreferenceControls* mTmpParent;// todo: voice key will be removed, class renamved, so it will have only one parent
 };
 
 LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key)
   : LLModalDialog(key),
-	mParent(NULL)
+	mParent(NULL),
+	mTmpParent(NULL)
 {
 }
 
@@ -201,15 +205,30 @@ LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog()
 BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask)
 {
 	BOOL result = TRUE;
+
+    if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT || key == KEY_NONE)
+    {
+        // temp
+        return false;
+    }
 	
+    // todo, same for escape
 	if (key == 'Q' && mask == MASK_CONTROL)
 	{
 		result = FALSE;
-	}
+        if (mTmpParent)
+        {
+            mTmpParent->onSetKey(KEY_NONE, MASK_NONE);
+        }
+    }
 	else if (mParent)
 	{
 		mParent->setKey(key);
 	}
+	else if (mTmpParent)
+	{
+		mTmpParent->onSetKey(key, mask);
+	}
 	closeFloater();
 	return result;
 }
@@ -217,11 +236,38 @@ BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask)
 BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
 {
     BOOL result = FALSE;
-    if (down
-        && (clicktype == CLICK_MIDDLE || clicktype == CLICK_BUTTON4 || clicktype == CLICK_BUTTON5)
-        && mask == 0)
+
+    if (clicktype == CLICK_LEFT)
+    {
+        if (down)
+        {
+            result = LLView::handleMouseDown(x, y, mask);
+        }
+        else
+        {
+            result = LLView::handleMouseUp(x, y, mask);
+        }
+    }
+    if (clicktype == LLMouseHandler::CLICK_LEFT)
+    {
+        result = LLView::handleDoubleClick(x, y, mask);
+    }
+    if (result)
+    {
+        return TRUE;
+    }
+    if (down && clicktype != LLMouseHandler::CLICK_RIGHT) //tmp
+        //&& (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5)
+        //&& mask == 0)
     {
-        mParent->setMouse(clicktype);
+        if (mParent)
+        {
+            mParent->setMouse(clicktype);
+        }
+        else if (mTmpParent)
+        {
+            mTmpParent->onSetMouse(clicktype, mask);
+        }
         result = TRUE;
         closeFloater();
     }
@@ -237,6 +283,11 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli
 void LLVoiceSetKeyDialog::onCancel(void* user_data)
 {
 	LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data;
+    // tmp needs 'no key' button
+    if (self->mTmpParent)
+        {
+            self->mTmpParent->onSetKey(KEY_NONE, MASK_NONE);
+        }
 	self->closeFloater();
 }
 
@@ -2914,6 +2965,273 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()
 	resetDirtyChilds();
 }
 
+
+//-------------------For LLPanelPreferenceControls' list---------------------------
+class LLGroupControlsListItem : public LLScrollListItem, public LLHandleProvider<LLGroupControlsListItem>
+{
+public:
+    LLGroupControlsListItem(const LLScrollListItem::Params& p)
+        : LLScrollListItem(p)
+    {
+    }
+
+    LLGroupControlsListItem(const LLScrollListItem::Params& p, const LLUUID& icon_id)
+        : LLScrollListItem(p), mIconId(icon_id)
+    {
+    }
+
+    void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
+    {
+        // todo: insert image and adjust rect
+        LLScrollListItem::draw(rect, fg_color, bg_color, highlight_color, column_padding);
+    }
+private:
+    LLUUID mIconId;
+};
+
+static const std::string tmp_typetostring[LLControlBindings::CONTROL_NUM_INDICES] = {
+    "control_view_actions",
+    "control_about",
+    "control_orbit",
+    "control_pan",
+    "control_world_map",
+    "control_zoom",
+    "control_interactions",
+    "control_build",
+    "control_drag",
+    "control_edit",
+    "control_menu",
+    "control_open",
+    "control_touch",
+    "control_wear",
+    "control_movements",
+    "control_moveto",
+    "control_sit",
+    "control_teleportto",
+    "control_forward",
+    "control_backward",
+    "control_left",
+    "control_right",
+    "control_lstrafe",
+    "control_rstrafe",
+    "control_jump",
+    "control_down",
+    "control_run",
+    "control_toggle_run",
+    "control_fly",
+    "control_mediacontent",
+    "control_parcel",
+    "control_media",
+    "control_voice",
+    "control_toggle_voice",
+    "control_reserved",
+    "control_menu",
+    "control_reserved_select",
+    "control_shift_select",
+    "control_cntrl_select"
+};
+
+//------------------------LLPanelPreferenceControls--------------------------------
+static LLPanelInjector<LLPanelPreferenceControls> t_pref_contrls("panel_preference_controls");
+
+BOOL LLPanelPreferenceControls::postBuild()
+{
+    //todo: on open instead of on the go
+    //todo: add pitch/yaw?
+    //todo: Scroll?
+    //todo: should be auto-expandable with menu items and should pull names from menu when possible
+
+
+    // populate list of controls
+    pControlsTable = getChild<LLScrollListCtrl>("controls_list");
+    populateControlTable();
+
+    pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this));
+
+    return TRUE;
+}
+
+void LLPanelPreferenceControls::populateControlTable()
+{
+    pControlsTable->clearRows();
+
+    // todo: subsections need sorting?
+    std::string label;
+    LLScrollListCell::Params cell_params;
+    // init basic cell params
+    cell_params.font = LLFontGL::getFontSansSerif();
+    cell_params.font_halign = LLFontGL::LEFT;
+    cell_params.column = "";
+    cell_params.value = label;
+
+    LLScrollListItem::Params item_params_blank;
+    cell_params.enabled = false;
+    item_params_blank.value = LLSD::Integer(-1);
+    item_params_blank.columns.add(cell_params);
+    cell_params.enabled = true;
+
+    for (U32 i = LLControlBindings::CONTROL_VIEW_ACTIONS; i < LLControlBindings::CONTROL_NUM_INDICES; i++)
+    {
+        switch (i)
+        {
+            case LLControlBindings::CONTROL_VIEW_ACTIONS:
+            {
+                // same as below, but without separator
+                LLScrollListItem::Params item_params;
+                item_params.value = LLSD::Integer(i);
+
+                label = getString(tmp_typetostring[i]);
+                cell_params.column = "lst_action";
+                cell_params.value = label;
+                //dummy cells
+                item_params.columns.add(cell_params);
+                cell_params.column = "lst_ctrl1";
+                cell_params.value = "";
+                item_params.columns.add(cell_params);
+                cell_params.column = "lst_ctrl2";
+                cell_params.value = "";
+                item_params.columns.add(cell_params);
+                LLUUID id;
+                LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id);
+                pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM);
+                break;
+            }
+            case LLControlBindings::CONTROL_INTERACTIONS:
+            case LLControlBindings::CONTROL_MOVEMENTS:
+            case LLControlBindings::CONTROL_MEDIACONTENT:
+            case LLControlBindings::CONTROL_RESERVED:
+            {
+                // insert blank
+                pControlsTable->addRow(item_params_blank, EAddPosition::ADD_BOTTOM);
+                // inster with icon
+                LLScrollListItem::Params item_params;
+                item_params.value = LLSD::Integer(i);
+
+                label = getString(tmp_typetostring[i]);
+                cell_params.column = "lst_action";
+                cell_params.value = label;
+                //dummy cells
+                item_params.columns.add(cell_params);
+                cell_params.column = "lst_ctrl1";
+                cell_params.value = "";
+                item_params.columns.add(cell_params);
+                cell_params.column = "lst_ctrl2";
+                cell_params.value = "";
+                item_params.columns.add(cell_params);
+                LLUUID id;
+                LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id);
+                pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM);
+                break;
+            }
+            default:
+            {
+                //default insert
+                LLScrollListItem::Params item_params;
+                item_params.value = LLSD::Integer(i);
+
+                // todo oddset
+                cell_params.column = "lst_action";
+                label = getString(tmp_typetostring[i]);
+                cell_params.value = label;
+                item_params.columns.add(cell_params);
+                cell_params.column = "lst_ctrl1";
+                cell_params.value = gControlBindings.getPrimaryControl((LLControlBindings::EControlTypes)i).asString();
+                item_params.columns.add(cell_params);
+                cell_params.column = "lst_ctrl2";
+                cell_params.value = gControlBindings.getSecondaryControl((LLControlBindings::EControlTypes)i).asString();
+                item_params.columns.add(cell_params);
+
+                pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM);
+                break;
+            }
+        }
+    }
+}
+
+void LLPanelPreferenceControls::cancel()
+{
+}
+
+void LLPanelPreferenceControls::saveSettings()
+{
+}
+
+void LLPanelPreferenceControls::resetDirtyChilds()
+{
+}
+
+bool LLPanelPreferenceControls::hasDirtyChilds()
+{
+    return false;
+}
+
+void LLPanelPreferenceControls::onListCommit()
+{
+    LLScrollListItem* item = pControlsTable->getFirstSelected();
+    if (item == NULL)
+    {
+        return;
+    }
+
+    S32 control = item->getValue().asInteger();
+
+    if (!gControlBindings.canAssignControl((LLControlBindings::EControlTypes)control))
+    {
+        return;
+    }
+    
+    // todo: add code to determine what cell was clicked, probably cells themself should be clickable
+
+    LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance<LLVoiceSetKeyDialog>("voice_set_key", LLSD(), TRUE);
+    if (dialog)
+    {
+        dialog->setTmpParent(this); // will be remade from being voice later
+    }
+}
+
+void LLPanelPreferenceControls::onSetKey(KEY key, MASK mask)
+{
+    LLScrollListItem* item = pControlsTable->getFirstSelected();
+    if (item == NULL)
+    {
+        return;
+    }
+
+    LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger();
+
+    if (!gControlBindings.canAssignControl(control))
+    {
+        return;
+    }
+
+    gControlBindings.registerPrimaryControl(control, LLMouseHandler::CLICK_NONE, key, mask);
+
+    // instead of populating, update single element
+    populateControlTable();
+}
+
+void LLPanelPreferenceControls::onSetMouse(LLMouseHandler::EClickType click, MASK mask)
+{
+
+    LLScrollListItem* item = pControlsTable->getFirstSelected();
+    if (item == NULL)
+    {
+        return;
+    }
+
+    LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger();
+
+    if (!gControlBindings.canAssignControl(control))
+    {
+        return;
+    }
+
+    gControlBindings.registerPrimaryControl(control, click, KEY_NONE, mask);
+
+    // instead of populating, update single element
+    populateControlTable();
+}
+
 LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key)
 	: LLFloater(key)
 {
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 9190ef8ebdf53e0751b01dd9bb6c9df40fa1eaed..74f55a7f91d40c3ec8b8fc1a0c7e211e6f236e87 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -293,6 +293,27 @@ class LLPanelPreferenceGraphics : public LLPanelPreference
 	LOG_CLASS(LLPanelPreferenceGraphics);
 };
 
+class LLPanelPreferenceControls : public LLPanelPreference
+{
+	LOG_CLASS(LLPanelPreferenceControls);
+public:
+	BOOL postBuild();
+	void populateControlTable();
+	void cancel();
+	void saveSettings();
+	void resetDirtyChilds();
+
+	void onListCommit();
+	void onSetKey(KEY key, MASK mask);
+	void onSetMouse(LLMouseHandler::EClickType click, MASK mask);
+
+protected:
+	bool hasDirtyChilds();
+
+private:
+	LLScrollListCtrl* pControlsTable;
+};
+
 class LLFloaterPreferenceGraphicsAdvanced : public LLFloater
 {
   public: 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 1dc1e65fe5a253d4d13e63065ed828d82fe48c69..7e6f3ef7bc83148c36b1cad724b27bf92ccb0510 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -996,7 +996,7 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 	}	
 	
 	LLSpatialGroup* group = drawablep->getSpatialGroup();
-	llassert(group != NULL);
+	//llassert(group != NULL);
 
 	if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
 	{
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index e7a8a78c14e9890b2fcdf5c2113775eb04c3b87c..676f06bcb95dbfedf83db7b3a7f61239591a2444 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -35,6 +35,7 @@
 #include "llnotificationsutil.h"
 #include "llsdserialize.h"
 #include "llui.h"
+#include "llkeybindings.h"
 #include "llkeyboard.h"
 #include "llagent.h"
 
@@ -690,7 +691,7 @@ void LLVoiceClient::keyDown(KEY key, MASK mask)
 		return;
 	}
 	
-	if (mPTTMouseButton == 0 && LLAgent::isActionAllowed("speak") && (key == mPTTKey))
+	if (LLAgent::isActionAllowed("speak") && gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask))
 	{
 		bool down = gKeyboard->getKeyDown(mPTTKey);
 		if (down)
@@ -702,7 +703,7 @@ void LLVoiceClient::keyDown(KEY key, MASK mask)
 }
 void LLVoiceClient::keyUp(KEY key, MASK mask)
 {
-	if (mPTTMouseButton == 0 && (key == mPTTKey))
+	if (gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask))
 	{
 		bool down = gKeyboard->getKeyDown(mPTTKey);
 		if (!down)
@@ -713,7 +714,7 @@ void LLVoiceClient::keyUp(KEY key, MASK mask)
 }
 void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down)
 {
-	if(mPTTMouseButton == click && LLAgent::isActionAllowed("speak"))
+	if(LLAgent::isActionAllowed("speak") && gControlBindings.canHandleMouse(LLControlBindings::CONTROL_VOICE, click, mask))
 	{
 		inputUserControlState(down);
 	}
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index 0e62d50072eb1940726e1c00a3fa296340d97419..ee730dcb013e1339b6cb5637a9e56d8356c7b3c1 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -169,6 +169,13 @@ https://accounts.secondlife.com/change_email/
          layout="topleft"
          help_topic="preferences_uploads_tab"
          name="uploads" />
+        <panel
+         class="panel_preference_controls"
+         filename="panel_preferences_controls.xml"
+         label="Controls"
+         layout="topleft"
+         help_topic="preferences_controls_tab"
+         name="controls" />
     </tab_container>
 
 </floater>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a1a2fd0598d5491478e8294bb82a268d5202993c
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<panel
+ border="true"
+ follows="all"
+ height="408"
+ label="Controls"
+ layout="topleft"
+ left="102"
+ name="controls"
+ top="1"
+ width="517">
+  <panel.string
+   name="control_view_actions">
+    View Actions
+  </panel.string>
+  <panel.string
+   name="control_about">
+    About/Profile
+  </panel.string>
+  <panel.string
+   name="control_orbit">
+    Orbit
+  </panel.string>
+  <panel.string
+   name="control_pan">
+    Pan
+  </panel.string>
+  <panel.string
+   name="control_world_map">
+    World Map
+  </panel.string>
+  <panel.string
+   name="control_zoom">
+    Zoom
+  </panel.string>
+  <panel.string
+   name="control_interactions">
+    Interactions
+  </panel.string>
+  <panel.string
+   name="control_build">
+    Build
+  </panel.string>
+  <panel.string
+   name="control_drag">
+    Drag
+  </panel.string>
+  <panel.string
+   name="control_edit">
+    Edit
+  </panel.string>
+  <panel.string
+   name="control_menu">
+    Menu
+  </panel.string>
+  <panel.string
+   name="control_open">
+    Open
+  </panel.string>
+  <panel.string
+   name="control_touch">
+    Touch
+  </panel.string>
+  <panel.string
+   name="control_wear">
+    Wear
+  </panel.string>
+  <panel.string
+   name="control_movements">
+    Move Actions
+  </panel.string>
+  <panel.string
+   name="control_moveto">
+    Move To
+  </panel.string>
+  <panel.string
+   name="control_sit">
+    Sit/Stand
+  </panel.string>
+  <panel.string
+   name="control_teleportto">
+    Teleport To
+  </panel.string>
+  <panel.string
+   name="control_forward">
+    Move Forward
+  </panel.string>
+  <panel.string
+   name="control_backward">
+    Move Backward
+  </panel.string>
+  <panel.string
+   name="control_left">
+    Left
+  </panel.string>
+  <panel.string
+   name="control_right">
+    Right
+  </panel.string>
+  <!--(check with move floater)-->
+  <panel.string
+   name="control_lstrafe">
+    Strafe left
+  </panel.string>
+  <panel.string
+   name="control_rstrafe">
+    Strafe right
+  </panel.string>
+  <panel.string
+   name="control_jump">
+    Strafe right
+  </panel.string>
+  <panel.string
+   name="control_down">
+    Strafe right
+  </panel.string>
+  <panel.string
+   name="control_run">
+    Run
+  </panel.string>
+  <panel.string
+   name="control_toggle_run">
+    Toggle Run
+  </panel.string>
+  <panel.string
+   name="control_fly">
+    Fly/Stop flying
+  </panel.string>
+  <panel.string
+   name="control_mediacontent">
+    Sound and Media
+  </panel.string>
+  <panel.string
+   name="control_parcel">
+    Play/Pause Parcel Media
+  </panel.string>
+  <panel.string
+   name="control_media">
+    Play/Stop All Media
+  </panel.string>
+  <panel.string
+   name="control_voice">
+    Voice
+  </panel.string>
+  <panel.string
+   name="control_toggle_voice">
+    Toggle Voice
+  </panel.string>
+  <panel.string
+   name="control_reserved">
+    Reserved Controls
+  </panel.string>
+  <!--
+   name="control_menu" not needed
+   -->
+  <panel.string
+   name="control_reserved_select">
+    Select
+  </panel.string>
+  <panel.string
+   name="control_shift_select">
+    Multi-Select
+  </panel.string>
+  <panel.string
+   name="control_cntrl_select">
+    Add to Selection
+  </panel.string>
+
+  <scroll_list
+   draw_heading="true"
+   follows="all"
+   layout="topleft"
+   column_padding="0"
+   top="3"
+   left="3"
+   bottom="-3"
+   right="-3"
+   multi_select="false"
+   name="controls_list">
+    <scroll_list.columns
+     relative_width="0.34"
+     label="Action"
+     name="lst_action" />
+    <scroll_list.columns
+     relative_width="0.33"
+     label="Primary Control Method"
+     name="lst_ctrl1" />
+    <scroll_list.columns
+     relative_width="0.33"
+     label="Secondary Control Method"
+     name="lst_ctrl2" />
+    <scroll_list.commit_callback
+      function="Pref.CommitControl" />
+  </scroll_list>
+
+</panel>