From e578491be761fefa34e4041458e2cf5badc81873 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 15 Jun 2020 20:35:58 +0300
Subject: SL-13418 Restored previously removed 'click on land' controls from
 'move & view'

According to UX UI engineer. Also adapted it to new system, but it needs a better solution.
---
 indra/newview/llfloaterpreference.cpp              | 212 ++++++++++++++++++++-
 indra/newview/llfloaterpreference.h                |  22 ++-
 indra/newview/llkeyconflict.cpp                    |  16 ++
 indra/newview/llkeyconflict.h                      |   5 +-
 .../default/xui/en/panel_preferences_move.xml      |  64 +++++++
 5 files changed, 312 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 604f054aa5..ac2b0172c7 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -311,6 +311,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 
 	sSkin = gSavedSettings.getString("SkinCurrent");
 
+	mCommitCallbackRegistrar.add("Pref.ClickActionChange",		boost::bind(&LLFloaterPreference::onClickActionChange, this));
+
 	gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged,  _2));	
 	gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged,  _2));	
 	gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged,  _2));
@@ -609,6 +611,8 @@ void LLFloaterPreference::cancel()
 	// reverts any changes to current skin
 	gSavedSettings.setString("SkinCurrent", sSkin);
 
+	updateClickActionViews();
+
 	LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy");
 	if (advanced_proxy_settings)
 	{
@@ -690,6 +694,9 @@ void LLFloaterPreference::onOpen(const LLSD& key)
 	onChangeTextureFolder();
 	onChangeSoundFolder();
 	onChangeAnimationFolder();
+
+	// Load (double-)click to walk/teleport settings.
+	updateClickActionViews();
 	
 	// Enabled/disabled popups, might have been changed by user actions
 	// while preferences floater was closed.
@@ -1486,6 +1493,7 @@ void LLFloaterPreference::refresh()
 	{
 		advanced->refresh();
 	}
+    updateClickActionViews();
 }
 
 void LLFloaterPreferenceGraphicsAdvanced::refresh()
@@ -1995,6 +2003,11 @@ void LLFloaterPreference::onClickAdvanced()
 	}
 }
 
+void LLFloaterPreference::onClickActionChange()
+{
+    updateClickActionControls();
+}
+
 void LLFloaterPreference::onClickPermsDefault()
 {
 	LLFloaterReg::showInstance("perms_default");
@@ -2032,6 +2045,86 @@ void LLFloaterPreference::onLogChatHistorySaved()
 	}
 }
 
+void LLFloaterPreference::updateClickActionControls()
+{
+    const int single_clk_action = getChild<LLComboBox>("single_click_action_combo")->getValue().asInteger();
+    const int double_clk_action = getChild<LLComboBox>("double_click_action_combo")->getValue().asInteger();
+
+    // Todo: This is a very ugly way to get access to keybindings.
+    // Reconsider possible options.
+    // Potential option: make constructor of LLKeyConflictHandler private
+    // but add a getter that will return shared pointer for specific
+    // mode, pointer should only exist so long as there are external users.
+    // In such case we won't need to do this 'dynamic_cast' nightmare.
+    // updateTable() can also be avoided
+    LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
+    for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
+        iter != tabcontainer->getChildList()->end(); ++iter)
+    {
+        LLView* view = *iter;
+        LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view);
+        if (panel)
+        {
+            panel->setKeyBind("walk_to",
+                              EMouseClickType::CLICK_LEFT,
+                              KEY_NONE,
+                              MASK_NONE,
+                              single_clk_action == 1);
+            
+            panel->setKeyBind("walk_to",
+                              EMouseClickType::CLICK_DOUBLELEFT,
+                              KEY_NONE,
+                              MASK_NONE,
+                              double_clk_action == 1);
+            
+            panel->setKeyBind("teleport_to",
+                              EMouseClickType::CLICK_DOUBLELEFT,
+                              KEY_NONE,
+                              MASK_NONE,
+                              double_clk_action == 2);
+
+            panel->updateTable();
+        }
+    }
+}
+
+void LLFloaterPreference::updateClickActionViews()
+{
+    bool click_to_walk = false;
+    bool dbl_click_to_walk = false;
+    bool dbl_click_to_teleport = false;
+
+    // Todo: This is a very ugly way to get access to keybindings.
+    // Reconsider possible options.
+    LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
+    for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
+        iter != tabcontainer->getChildList()->end(); ++iter)
+    {
+        LLView* view = *iter;
+        LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view);
+        if (panel)
+        {
+            click_to_walk = panel->canKeyBindHandle("walk_to",
+                EMouseClickType::CLICK_LEFT,
+                KEY_NONE,
+                MASK_NONE);
+
+            dbl_click_to_walk = panel->canKeyBindHandle("walk_to",
+                EMouseClickType::CLICK_DOUBLELEFT,
+                KEY_NONE,
+                MASK_NONE);
+
+            dbl_click_to_teleport = panel->canKeyBindHandle("teleport_to",
+                EMouseClickType::CLICK_DOUBLELEFT,
+                KEY_NONE,
+                MASK_NONE);
+        }
+    }
+
+	getChild<LLComboBox>("single_click_action_combo")->setValue((int)click_to_walk);
+	getChild<LLComboBox>("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk);
+}
+
 void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param)
 {
 	LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue()));
@@ -2856,7 +2949,7 @@ void LLPanelPreferenceControls::saveSettings()
     }
 
     S32 mode = pKeyModeBox->getValue().asInteger();
-    if (mConflictHandler[mode].empty())
+    if (mConflictHandler[mode].empty() || pControlsTable->isEmpty())
     {
         regenerateControls();
     }
@@ -2951,6 +3044,13 @@ void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notificati
             mConflictHandler[i].resetToDefaults();
             // Apply changes to viewer as 'temporary'
             mConflictHandler[i].saveToSettings(true);
+
+            // notify comboboxes in move&view about potential change
+            LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+            if (instance)
+            {
+                instance->updateClickActionViews();
+            }
         }
 
         updateTable();
@@ -2960,6 +3060,16 @@ void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notificati
         // Apply changes to viewer as 'temporary'
         mConflictHandler[mEditingMode].saveToSettings(true);
 
+        if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON)
+        {
+            // notify comboboxes in move&view about potential change
+            LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+            if (instance)
+            {
+                instance->updateClickActionViews();
+            }
+        }
+
         updateTable();
         break;
     case 2: // Cancel
@@ -2969,7 +3079,80 @@ void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notificati
     }
 }
 
-// todo: copy onSetKeyBind to interface and inherit from interface
+// Bypass to let Move & view read values without need to create own key binding handler
+// Assumes third person view
+// Might be better idea to just move whole mConflictHandler into LLFloaterPreference
+bool LLPanelPreferenceControls::canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask)
+{
+    S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
+    if (mConflictHandler[mode].empty())
+    {
+        // opening for first time
+        mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON);
+    }
+
+    return mConflictHandler[mode].canHandleControl(control, click, key, mask);
+}
+
+// Bypass to let Move & view modify values without need to create own key binding handler
+// Assumes third person view
+// Might be better idea to just move whole mConflictHandler into LLFloaterPreference
+void LLPanelPreferenceControls::setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set)
+{
+    S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
+    if (mConflictHandler[mode].empty())
+    {
+        // opening for first time
+        mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON);
+    }
+
+    if (!mConflictHandler[mode].canAssignControl(mEditingControl))
+    {
+        return;
+    }
+
+    bool already_recorded = mConflictHandler[mode].canHandleControl(control, click, key, mask);
+    if (set)
+    {
+        if (already_recorded)
+        {
+            // nothing to do
+            return;
+        }
+
+        // find free spot to add data, if no free spot, assign to first
+        S32 index = 0;
+        for (S32 i = 0; i < 3; i++)
+        {
+            if (mConflictHandler[mode].getControl(control, i).isEmpty())
+            {
+                index = i;
+                break;
+            }
+        }
+        mConflictHandler[mode].registerControl(control, index, click, key, mask, true);
+    }
+    else if (!set)
+    {
+        if (!already_recorded)
+        {
+            // nothing to do
+            return;
+        }
+
+        // find specific control and reset it
+        for (S32 i = 0; i < 3; i++)
+        {
+            LLKeyData data = mConflictHandler[mode].getControl(control, i);
+            if (data.mMouse == click && data.mKey == key && data.mMask == mask)
+            {
+                mConflictHandler[mode].clearControl(control, i);
+            }
+        }
+    }
+}
+
+// from LLSetKeybindDialog's interface
 bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
 {
     if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
@@ -3001,6 +3184,21 @@ bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
     }
 
     updateTable();
+
+    if ((mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
+        && (mEditingControl == "walk_to"
+            || mEditingControl == "teleport_to"
+            || click == CLICK_LEFT
+            || click == CLICK_DOUBLELEFT))
+    {
+        // notify comboboxes in move&view about potential change
+        LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+        if (instance)
+        {
+            instance->updateClickActionViews();
+        }
+    }
+
     return true;
 }
 
@@ -3034,6 +3232,16 @@ void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes)
         }
     }
     updateTable();
+
+    if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
+    {
+        // notify comboboxes in move&view about potential change
+        LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+        if (instance)
+        {
+            instance->updateClickActionViews();
+        }
+    }
 }
 
 void LLPanelPreferenceControls::onCancelKeyBind()
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index ea6e1070cd..066deb97ee 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -106,6 +106,8 @@ public:
 	void selectPrivacyPanel();
 	void selectChatPanel();
 	void getControlNames(std::vector<std::string>& names);
+	// updates click/double-click action controls depending on values from settings.xml
+	void updateClickActionViews();
 
 protected:	
 	void		onBtnOK(const LLSD& userdata);
@@ -131,6 +133,11 @@ protected:
 	// callback for when client turns on impostors
 	void onAvatarImpostorsEnable();
 
+	// callback for commit in the "Single click on land" and "Double click on land" comboboxes.
+	void onClickActionChange();
+	// updates click/double-click action keybindngs depending on view values
+	void updateClickActionControls();
+
 public:
 	// This function squirrels away the current values of the controls so that
 	// cancel() can restore them.	
@@ -304,9 +311,20 @@ public:
 	void onModeCommit();
 	void onRestoreDefaultsBtn();
 	void onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response);
+
+    // Bypass to let Move & view read values without need to create own key binding handler
+    // Todo: consider a better way to share access to keybindings
+    bool canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask);
+    // Bypasses to let Move & view modify values without need to create own key binding handler
+    void setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set /*set or reset*/ );
+
+    // from interface
 	/*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
     /*virtual*/ void onDefaultKeyBind(bool all_modes);
-	/*virtual*/ void onCancelKeyBind();
+    /*virtual*/ void onCancelKeyBind();
+
+    // Updates keybindings from storage to table
+    void updateTable();
 
 private:
 	// reloads settings, discards current changes, updates table
@@ -319,8 +337,6 @@ private:
 
 	// Cleans content and then adds content from xml files according to current mEditingMode
 	void populateControlTable();
-	// Updates keybindings from storage to table
-	void updateTable();
 
 	LLScrollListCtrl* pControlsTable;
 	LLComboBox *pKeyModeBox;
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 5f966624ca..b426dc14fc 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -217,6 +217,22 @@ bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32
     return false;
 }
 
+bool LLKeyConflictHandler::clearControl(const std::string &control_name, U32 data_index)
+{
+    if (control_name.empty())
+    {
+        return false;
+    }
+    LLKeyConflict &type_data = mControlsMap[control_name];
+    if (!type_data.mAssignable)
+    {
+        // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it
+        return false;
+    }
+    type_data.mKeyBind.resetKeyData(data_index);
+    return true;
+}
+
 LLKeyData LLKeyConflictHandler::getControl(const std::string &control_name, U32 index)
 {
     if (control_name.empty())
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 5451c16ae2..7566303cdd 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -86,8 +86,8 @@ public:
     // @control_name - see REGISTER_KEYBOARD_ACTION in llviewerinput for avaliable options,
     // usually this is just name of the function
     // @data_index - single control (function) can have multiple key combinations trigering
-    // it, this index indicates combination function will change/add note that preferences
-    // floater can only display up to 3 options, but data_index can be bigger then that
+    // it, this index indicates combination function will change/add; Note that preferences
+    // floater can only display up to 3 options, but data_index can be bigger than that
     // @mouse_ind - mouse action (middle click, MB5 etc)
     // @key - keyboard key action
     // @mask - shift/ctrl/alt flags
@@ -95,6 +95,7 @@ public:
     // is active) or ignore not expected masks as long as expected mask is present
     // (ctrl+K will be triggered if ctrl+shift+K is active)
     bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
+    bool clearControl(const std::string &control_name, U32 data_index);
 
     LLKeyData getControl(const std::string &control_name, U32 data_index);
 
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
index d106456b31..8794e3bf95 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
@@ -195,6 +195,70 @@
    name="invert_mouse"
    top_delta="0"
    width="128" />
+  <text
+   follows="left|top"
+   type="string"
+   length="1"
+   height="10"
+   layout="topleft"
+   left="86"
+   name="single_click_action_lbl"
+   width="150"
+   top_pad="20">
+    Single click on land:
+  </text>
+  <combo_box
+   height="23"
+   layout="topleft"
+   left_pad="10"
+   top_delta="-6"
+   name="single_click_action_combo"
+   width="200">
+    <combo_box.item
+     label="No action"
+     name="0"
+     value="0"/>
+    <combo_box.item
+     label="Move to clicked point"
+     name="1"
+     value="1"/>
+    <combo_box.commit_callback
+     function="Pref.ClickActionChange"/>
+  </combo_box>
+  <text
+   follows="left|top"
+   type="string"
+   length="1"
+   height="10"
+   layout="topleft"
+   left="86"
+   name="double_click_action_lbl"
+   width="150"
+   top_pad="12">
+    Double click on land:
+  </text>
+  <combo_box
+   height="23"
+   layout="topleft"
+   left_pad="10"
+   top_delta="-6"
+   name="double_click_action_combo"
+   width="200">
+    <combo_box.item
+     label="No action"
+     name="0"
+     value="0"/>
+    <combo_box.item
+     label="Move to clicked point"
+     name="1"
+     value="1"/>
+    <combo_box.item
+     label="Teleport to clicked point"
+     name="2"
+     value="2"/>
+    <combo_box.commit_callback
+     function="Pref.ClickActionChange"/>
+  </combo_box>
   <button
    height="23"
    label="Other Devices"
-- 
cgit v1.2.3