From f912fecad50cd3f34295ce87e0ebc9476214616a Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Fri, 20 Mar 2020 13:09:42 +0100
Subject: [PATCH] 3DConnexion devices: added option to swap y/z translations

---
 src/slic3r/GUI/AppConfig.cpp         |  3 ++-
 src/slic3r/GUI/AppConfig.hpp         |  4 +++-
 src/slic3r/GUI/Mouse3DController.cpp | 30 ++++++++++++++++++++--------
 src/slic3r/GUI/Mouse3DController.hpp |  4 +++-
 4 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp
index 212d7bcf2..61d062010 100644
--- a/src/slic3r/GUI/AppConfig.cpp
+++ b/src/slic3r/GUI/AppConfig.cpp
@@ -280,7 +280,7 @@ void AppConfig::set_recent_projects(const std::vector<std::string>& recent_proje
     }
 }
 
-void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed)
+void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz_translations)
 {
     std::string key = std::string("mouse_device:") + name;
     auto it = m_storage.find(key);
@@ -293,6 +293,7 @@ void AppConfig::set_mouse_device(const std::string& name, double translation_spe
     it->second["rotation_speed"] = std::to_string(rotation_speed);
     it->second["rotation_deadzone"] = std::to_string(rotation_deadzone);
     it->second["zoom_speed"] = std::to_string(zoom_speed);
+    it->second["swap_yz_translations"] = swap_yz_translations ? "1" : "0";
 }
 
 std::vector<std::string> AppConfig::get_mouse_device_names() const
diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp
index c1c4607ec..0b55effb3 100644
--- a/src/slic3r/GUI/AppConfig.hpp
+++ b/src/slic3r/GUI/AppConfig.hpp
@@ -141,7 +141,7 @@ public:
     std::vector<std::string> get_recent_projects() const;
     void set_recent_projects(const std::vector<std::string>& recent_projects);
 
-	void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed);
+	void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz_translations);
 	std::vector<std::string> get_mouse_device_names() const;
 	bool get_mouse_device_translation_speed(const std::string& name, double& speed) const
 		{ return get_3dmouse_device_numeric_value(name, "translation_speed", speed); }
@@ -153,6 +153,8 @@ public:
 		{ return get_3dmouse_device_numeric_value(name, "rotation_deadzone", deadzone); }
 	bool get_mouse_device_zoom_speed(const std::string& name, double& speed) const
 		{ return get_3dmouse_device_numeric_value(name, "zoom_speed", speed); }
+	bool get_mouse_device_swap_yz_translations(const std::string& name, bool& swap) const
+		{ return get_3dmouse_device_numeric_value(name, "swap_yz_translations", swap); }
 
 	static const std::string SECTION_FILAMENTS;
     static const std::string SECTION_MATERIALS;
diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp
index dcce52ae8..2d97efd3d 100644
--- a/src/slic3r/GUI/Mouse3DController.cpp
+++ b/src/slic3r/GUI/Mouse3DController.cpp
@@ -150,8 +150,8 @@ bool Mouse3DController::State::apply(const Mouse3DController::Params &params, Ca
 
     for (const QueueItem &input_queue_item : input_queue) {
     	if (input_queue_item.is_translation()) {
-	        const Vec3d& translation = input_queue_item.vector;
-	        double zoom_factor = camera.min_zoom() / camera.get_zoom();
+            Vec3d translation = params.swap_yz_translations ? Vec3d(input_queue_item.vector(0), input_queue_item.vector(2), input_queue_item.vector(1)) : input_queue_item.vector;
+            double zoom_factor = camera.min_zoom() / camera.get_zoom();
 	        camera.set_target(camera.get_target() + zoom_factor * params.translation.scale * (translation.x() * camera.get_dir_right() + translation.z() * camera.get_dir_up()));
             if (translation.y() != 0.0)
                 camera.update_zoom(params.zoom.scale * translation.y());
@@ -185,19 +185,22 @@ void Mouse3DController::load_config(const AppConfig &appconfig)
 	    double translation_deadzone = Params::DefaultTranslationDeadzone;
 	    float  rotation_deadzone 	= Params::DefaultRotationDeadzone;
 	    double zoom_speed 			= 2.0;
-	    appconfig.get_mouse_device_translation_speed(device_name, translation_speed);
+        bool   swap_yz_translations = false;
+        appconfig.get_mouse_device_translation_speed(device_name, translation_speed);
 	    appconfig.get_mouse_device_translation_deadzone(device_name, translation_deadzone);
 	    appconfig.get_mouse_device_rotation_speed(device_name, rotation_speed);
 	    appconfig.get_mouse_device_rotation_deadzone(device_name, rotation_deadzone);
 	    appconfig.get_mouse_device_zoom_speed(device_name, zoom_speed);
-	    // clamp to valid values
+        appconfig.get_mouse_device_swap_yz_translations(device_name, swap_yz_translations);
+        // clamp to valid values
 	    Params params;
 	    params.translation.scale = Params::DefaultTranslationScale * std::clamp(translation_speed, 0.1, 10.0);
 	    params.translation.deadzone = std::clamp(translation_deadzone, 0.0, Params::MaxTranslationDeadzone);
 	    params.rotation.scale = Params::DefaultRotationScale * std::clamp(rotation_speed, 0.1f, 10.0f);
 	    params.rotation.deadzone = std::clamp(rotation_deadzone, 0.0f, Params::MaxRotationDeadzone);
 	    params.zoom.scale = Params::DefaultZoomScale * std::clamp(zoom_speed, 0.1, 10.0);
-	    m_params_by_device[device_name] = std::move(params);
+        params.swap_yz_translations = swap_yz_translations;
+        m_params_by_device[device_name] = std::move(params);
 	}
 }
 
@@ -210,9 +213,9 @@ void Mouse3DController::save_config(AppConfig &appconfig) const
 		const std::string &device_name = key_value_pair.first;
 		const Params      &params      = key_value_pair.second;
 	    // Store current device parameters into the config
-	    appconfig.set_mouse_device(device_name, params.translation.scale / Params::DefaultTranslationScale, params.translation.deadzone,
-	        params.rotation.scale / Params::DefaultRotationScale, params.rotation.deadzone, params.zoom.scale / Params::DefaultZoomScale);
-	}
+        appconfig.set_mouse_device(device_name, params.translation.scale / Params::DefaultTranslationScale, params.translation.deadzone,
+            params.rotation.scale / Params::DefaultRotationScale, params.rotation.deadzone, params.zoom.scale / Params::DefaultZoomScale, params.swap_yz_translations);
+    }
 }
 
 bool Mouse3DController::apply(Camera& camera)
@@ -315,6 +318,17 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
             	params_changed = true;
             }
 
+            ImGui::Separator();
+            ImGui::PushStyleColor(ImGuiCol_Text, color);
+            imgui.text(_(L("Options:")));
+            ImGui::PopStyleColor();
+
+            bool swap_yz = params_copy.swap_yz_translations;
+            if (imgui.checkbox("Swap Y/Z translations", swap_yz)) {
+                params_copy.swap_yz_translations = swap_yz;
+                params_changed = true;
+            }
+
 #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
             ImGui::Separator();
             ImGui::Separator();
diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp
index 8f03606b0..d21b970db 100644
--- a/src/slic3r/GUI/Mouse3DController.hpp
+++ b/src/slic3r/GUI/Mouse3DController.hpp
@@ -56,7 +56,9 @@ class Mouse3DController
         // The effects of changing this value can be tested by setting ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT to 1
         // and playing with the imgui dialog which shows by pressing CTRL+M
         size_t 					 input_queue_max_size { 15 };
-	};
+        // Whether to swap Y/Z axis when translating or not.
+        bool 					 swap_yz_translations{ false };
+    };
 
 	// Queue of the 3DConnexion input events (translations, rotations, button presses).
     class State