OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::Mouse3DController Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/Mouse3DController.hpp>

Collaboration diagram for Slic3r::GUI::Mouse3DController:

Classes

struct  Params
class  State

Public Member Functions

void load_config (const AppConfig &appconfig)
void save_config (AppConfig &appconfig) const
void init ()
void shutdown ()
bool connected () const
bool apply (Camera &camera)
bool can_show_settings_dialog () const
bool is_settings_dialog_shown () const
void show_settings_dialog (bool show)
void render_settings_dialog (GLCanvas3D &canvas) const

Private Types

typedef std::array< unsigned char, 13 > DataPacketRaw

Private Member Functions

bool connect_device ()
void disconnect_device ()
void run ()
void collect_input ()

Static Private Member Functions

static bool handle_input (const DataPacketRaw &packet, const int packet_length, const Params &params, State &state_in_out)
static bool handle_packet (const DataPacketRaw &packet, const int packet_length, const Params &params, State &state_in_out)
static bool handle_packet_translation (const DataPacketRaw &packet, const Params &params, State &state_in_out)
static bool handle_packet_rotation (const DataPacketRaw &packet, unsigned int first_byte, const Params &params, State &state_in_out)
static bool handle_packet_button (const DataPacketRaw &packet, unsigned int packet_size, const Params &params, State &state_in_out)

Private Attributes

Params m_params
Params m_params_ui
bool m_params_ui_changed { false }
std::mutex m_params_ui_mutex
std::map< std::string, Params > m_params_by_device
State m_state
std::atomic< bool > m_connected { false }
std::string m_device_str
std::thread m_thread
hid_device * m_device { nullptr }
bool m_stop { false }
std::mutex m_stop_condition_mutex
std::condition_variable m_stop_condition
bool m_show_settings_dialog { false }
bool m_settings_dialog_closed_by_user { false }

Detailed Description

Member Typedef Documentation

◆ DataPacketRaw

typedef std::array<unsigned char, 13> Slic3r::GUI::Mouse3DController::DataPacketRaw
private

Member Function Documentation

◆ apply()

bool Slic3r::GUI::Mouse3DController::apply ( Camera & camera)
435{
436 // check if the user unplugged the device
437 if (! m_connected) {
438 // hides the settings dialog if the user un-plug the device
441 }
442
443#ifdef _WIN32
444 {
445 std::scoped_lock<std::mutex> lock(m_params_ui_mutex);
448 m_params_ui_changed = false;
449 }
450 }
451#endif // _WIN32
452
453 return m_state.apply(m_params, camera);
454}
State m_state
Definition Mouse3DController.hpp:159
Params m_params
Definition Mouse3DController.hpp:147
bool m_settings_dialog_closed_by_user
Definition Mouse3DController.hpp:181
Params m_params_ui
Definition Mouse3DController.hpp:149
std::atomic< bool > m_connected
Definition Mouse3DController.hpp:160
bool m_show_settings_dialog
Definition Mouse3DController.hpp:179
std::mutex m_params_ui_mutex
Definition Mouse3DController.hpp:151
bool m_params_ui_changed
Definition Mouse3DController.hpp:150
@ lock
Definition GLGizmoEmboss.cpp:209

References m_connected, m_params, m_params_ui, m_params_ui_changed, m_params_ui_mutex, m_settings_dialog_closed_by_user, m_show_settings_dialog, and m_state.

◆ can_show_settings_dialog()

bool Slic3r::GUI::Mouse3DController::can_show_settings_dialog ( ) const
457{
458#ifdef _WIN32
459 if (wxGetApp().app_config->get("use_legacy_3DConnexion") != "true")
460 return false;
461#endif // _WIN32
462 return this->connected();
463}
bool connected() const
Definition Mouse3DController.hpp:197

References connected().

Referenced by Slic3r::GUI::GLCanvas3D::handle_shortcut().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ collect_input()

void Slic3r::GUI::Mouse3DController::collect_input ( )
private
1238{
1239#ifdef HAVE_SPNAV
1240 // Read packet, block maximum 100 ms. That means when closing the application, closing the application will be delayed by 100 ms.
1241 int fd = spnav_fd();
1242
1243 if (fd != -1) {
1244 fd_set fds;
1245 struct timeval tv = {.tv_sec = 0, .tv_usec = 100000};
1246
1247 FD_ZERO(&fds);
1248 FD_SET(fd, &fds);
1249 if (select(fd + 1, &fds, NULL, NULL, &tv) == 1) {
1250 spnav_event ev = {};
1251 switch (spnav_poll_event(&ev)) {
1252 case SPNAV_EVENT_MOTION: {
1253 Vec3d translation(-convert_spnav_input(ev.motion.x), convert_spnav_input(ev.motion.y), -convert_spnav_input(ev.motion.z));
1254 if (!translation.isApprox(Vec3d::Zero())) {
1255 m_state.append_translation(translation, m_params.input_queue_max_size);
1256 }
1257 Vec3f rotation(convert_spnav_input(ev.motion.rx), convert_spnav_input(ev.motion.ry), -convert_spnav_input(ev.motion.rz));
1258 if (!rotation.isApprox(Vec3f::Zero())) {
1259 m_state.append_rotation(rotation, m_params.input_queue_max_size);
1260 }
1261 break;
1262 }
1263 case SPNAV_EVENT_BUTTON:
1264 if (ev.button.press)
1265 m_state.append_button((unsigned int)ev.button.bnum, m_params.input_queue_max_size);
1266 break;
1267 }
1268 wxGetApp().plater()->set_current_canvas_as_dirty();
1269 // ask for an idle event to update 3D scene
1270 wxWakeUpIdle();
1271 }
1272 }
1273#else
1274 DataPacketRaw packet = { 0 };
1275 // Read packet, block maximum 100 ms. That means when closing the application, closing the application will be delayed by 100 ms.
1276 int res = hid_read_timeout(m_device, packet.data(), packet.size(), 100);
1277 if (res < 0) {
1278 // An error occourred (device detached from pc ?). Close the 3Dconnexion device.
1279 this->disconnect_device();
1280 } else
1281 this->handle_input(packet, res, m_params, m_state);
1282#endif
1283}
hid_device * m_device
Definition Mouse3DController.hpp:166
std::array< unsigned char, 13 > DataPacketRaw
Definition Mouse3DController.hpp:239
void disconnect_device()
Definition Mouse3DController.cpp:1202
static bool handle_input(const DataPacketRaw &packet, const int packet_length, const Params &params, State &state_in_out)
Definition Mouse3DController.cpp:1303
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:65

References disconnect_device(), handle_input(), m_device, m_params, and m_state.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ connect_device()

bool Slic3r::GUI::Mouse3DController::connect_device ( )
private
943{
944 if (m_stop || wxGetApp().app_config->get("skip_3dmouse_detect") == "true")
945 return false;
946
947 {
948 // Wait for 2 seconds, but cancellable by m_stop.
949 std::unique_lock<std::mutex> lock(m_stop_condition_mutex);
950#ifdef _WIN32
951 // Wait indifinetely for the stop signal.
952 m_stop_condition.wait(lock, [this]{ return m_stop || m_wakeup; });
953 m_wakeup = false;
954#else
955 m_stop_condition.wait_for(lock, std::chrono::seconds(2), [this]{ return m_stop; });
956#endif
957 }
958
959 if (m_stop)
960 return false;
961
962 // Enumerates devices
963 hid_device_info* devices = hid_enumerate(0, 0);
964 if (devices == nullptr) {
965 BOOST_LOG_TRIVIAL(trace) << "Mouse3DController::connect_device() - no HID device enumerated.";
966 return false;
967 }
968
969#ifdef _WIN32
970 BOOST_LOG_TRIVIAL(trace) << "Mouse3DController::connect_device() - enumerating HID devices.";
971#endif // _WIN32
972
973 // Searches for 1st connected 3Dconnexion device
974 struct DeviceData
975 {
976 std::string path;
977 unsigned short usage_page;
978 unsigned short usage;
979
980 DeviceData()
981 : path(""), usage_page(0), usage(0)
982 {}
983 DeviceData(const std::string& path, unsigned short usage_page, unsigned short usage)
984 : path(path), usage_page(usage_page), usage(usage)
985 {}
986
987 // https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
988 // Usage page 1 - Generic Desktop Controls
989 // Usage page 1, usage 8 - Multi-axis Controller
990 bool has_valid_usage() const { return usage_page == 1 && usage == 8; }
991 };
992
993#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
994 hid_device_info* cur = devices;
995 std::cout << std::endl << "======================================================================================================================================" << std::endl;
996 std::cout << "Detected devices:" << std::endl;
997 while (cur != nullptr) {
998 std::cout << "\"";
999 std::wcout << ((cur->manufacturer_string != nullptr) ? cur->manufacturer_string : L"Unknown");
1000 std::cout << "/";
1001 std::wcout << ((cur->product_string != nullptr) ? cur->product_string : L"Unknown");
1002 std::cout << "\" code: " << cur->vendor_id << "/" << cur->product_id << " (" << std::hex << cur->vendor_id << "/" << cur->product_id << std::dec << ")";
1003 std::cout << " serial number: '";
1004 std::wcout << ((cur->serial_number != nullptr) ? cur->serial_number : L"Unknown");
1005 std::cout << "' usage page: " << cur->usage_page << " usage: " << cur->usage << " interface number: " << cur->interface_number << std::endl;
1006
1007 cur = cur->next;
1008 }
1009#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1010
1011 // When using 3Dconnexion universal receiver, multiple devices are detected sharing the same vendor_id and product_id.
1012 // To choose from them the right one we use:
1013 // On Windows and Mac: usage_page == 1 and usage == 8
1014 // On Linux: as usage_page and usage are not defined (see hidapi.h) we try all detected devices until one is succesfully open
1015 // When only a single device is detected, as for wired connections, vendor_id and product_id are enough
1016
1017 // First we count all the valid devices from the enumerated list,
1018
1019 hid_device_info* current = devices;
1020 typedef std::pair<unsigned short, unsigned short> DeviceIds;
1021 typedef std::vector<DeviceData> DeviceDataList;
1022 typedef std::map<DeviceIds, DeviceDataList> DetectedDevices;
1023 DetectedDevices detected_devices;
1024#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1025 std::cout << std::endl << "Detected 3D connexion devices:" << std::endl;
1026#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1027 while (current != nullptr) {
1028 unsigned short vendor_id = 0;
1029 unsigned short product_id = 0;
1030
1031 for (size_t i = 0; i < _3DCONNEXION_VENDORS.size(); ++i) {
1032 if (_3DCONNEXION_VENDORS[i] == current->vendor_id) {
1033 vendor_id = current->vendor_id;
1034 break;
1035 }
1036 }
1037
1038 if (vendor_id != 0) {
1039 for (size_t i = 0; i < _3DCONNEXION_DEVICES.size(); ++i) {
1040 if (_3DCONNEXION_DEVICES[i] == current->product_id) {
1041 product_id = current->product_id;
1042 DeviceIds detected_device(vendor_id, product_id);
1043 DetectedDevices::iterator it = detected_devices.find(detected_device);
1044 if (it == detected_devices.end())
1045 it = detected_devices.insert(DetectedDevices::value_type(detected_device, DeviceDataList())).first;
1046
1047 it->second.emplace_back(current->path, current->usage_page, current->usage);
1048
1049#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1050 std::wcout << "\"" << ((current->manufacturer_string != nullptr) ? current->manufacturer_string : L"Unknown");
1051 std::cout << "/";
1052 std::wcout << ((current->product_string != nullptr) ? current->product_string : L"Unknown");
1053 std::cout << "\" code: " << current->vendor_id << "/" << current->product_id << " (" << std::hex << current->vendor_id << "/" << current->product_id << std::dec << ")";
1054 std::cout << " serial number: '";
1055 std::wcout << ((current->serial_number != nullptr) ? current->serial_number : L"Unknown");
1056 std::cout << "' usage page: " << current->usage_page << " usage: " << current->usage << std::endl;
1057#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1058 }
1059 }
1060 }
1061
1062 current = current->next;
1063 }
1064
1065 // Free enumerated devices
1066 hid_free_enumeration(devices);
1067
1068 if (detected_devices.empty())
1069 return false;
1070
1071 std::string path;
1072 unsigned short vendor_id = 0;
1073 unsigned short product_id = 0;
1074
1075 // Then we'll decide the choosing logic to apply in dependence of the device count and operating system
1076
1077 for (const DetectedDevices::value_type& device : detected_devices) {
1078 if (device.second.size() == 1) {
1079#if defined(__linux__)
1080 hid_device* test_device = hid_open(device.first.first, device.first.second, nullptr);
1081 if (test_device == nullptr) {
1082 BOOST_LOG_TRIVIAL(error) << "3DConnexion device cannot be opened: " << device.second.front().path <<
1083 " You may need to update /etc/udev/rules.d";
1084 } else {
1085 hid_close(test_device);
1086#else
1087 if (device.second.front().has_valid_usage()) {
1088#endif // __linux__
1089 vendor_id = device.first.first;
1090 product_id = device.first.second;
1091 break;
1092 }
1093 }
1094 else {
1095 bool found = false;
1096#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1097 std::cout << std::endl;
1098#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1099 for (const DeviceData& data : device.second) {
1100#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1101 std::cout << "Test device: " << std::hex << device.first.first << std::dec << "/" << std::hex << device.first.second << std::dec << " \"" << data.path << "\"";
1102#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1103
1104#ifdef __linux__
1105 hid_device* test_device = hid_open_path(data.path.c_str());
1106 if (test_device != nullptr) {
1107 path = data.path;
1108 vendor_id = device.first.first;
1109 product_id = device.first.second;
1110 found = true;
1111#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1112 std::cout << "-> PASSED" << std::endl;
1113#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1114 hid_close(test_device);
1115 break;
1116 }
1117#else // !__linux__
1118 if (data.has_valid_usage()) {
1119 path = data.path;
1120 vendor_id = device.first.first;
1121 product_id = device.first.second;
1122 found = true;
1123#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1124 std::cout << "-> PASSED" << std::endl;
1125#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1126 break;
1127 }
1128#endif // __linux__
1129 else {
1130 BOOST_LOG_TRIVIAL(error) << "3DConnexion device cannot be opened: " << data.path <<
1131 " You may need to update /etc/udev/rules.d";
1132#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1133 std::cout << "-> NOT PASSED" << std::endl;
1134#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1135 }
1136 }
1137
1138 if (found)
1139 break;
1140 }
1141 }
1142
1143 if (path.empty()) {
1144 if ((vendor_id != 0) && (product_id != 0)) {
1145 // Open the 3Dconnexion device using vendor_id and product_id
1146#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1147 std::cout << std::endl << "Opening device: " << std::hex << vendor_id << std::dec << "/" << std::hex << product_id << std::dec << " using hid_open()" << std::endl;
1148#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1149 m_device = hid_open(vendor_id, product_id, nullptr);
1150 }
1151 else
1152 return false;
1153 }
1154 else {
1155 // Open the 3Dconnexion device using the device path
1156#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1157 std::cout << std::endl << "Opening device: " << std::hex << vendor_id << std::dec << "/" << std::hex << product_id << std::dec << "\"" << path << "\" using hid_open_path()" << std::endl;
1158#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1159 m_device = hid_open_path(path.c_str());
1160 }
1161
1162 if (m_device != nullptr) {
1163 wchar_t buffer[1024];
1164 hid_get_manufacturer_string(m_device, buffer, 1024);
1165 m_device_str = into_u8(buffer);
1166 // #3479 seems to show that sometimes an extra whitespace is added, so we remove it
1167 boost::algorithm::trim(m_device_str);
1168
1169 hid_get_product_string(m_device, buffer, 1024);
1170 m_device_str += "/" + into_u8(buffer);
1171 // #3479 seems to show that sometimes an extra whitespace is added, so we remove it
1172 boost::algorithm::trim(m_device_str);
1173
1174 BOOST_LOG_TRIVIAL(info) << "Connected 3DConnexion device:";
1175 BOOST_LOG_TRIVIAL(info) << "Manufacturer/product: " << m_device_str;
1176 BOOST_LOG_TRIVIAL(info) << "Manufacturer id.....: " << vendor_id << " (" << std::hex << vendor_id << std::dec << ")";
1177 BOOST_LOG_TRIVIAL(info) << "Product id..........: " << product_id << " (" << std::hex << product_id << std::dec << ")";
1178 if (!path.empty())
1179 BOOST_LOG_TRIVIAL(info) << "Path................: '" << path << "'";
1180#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1181 std::cout << "Opened device." << std::endl;
1182#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1183 // Copy the parameters for m_device_str into the current parameters.
1184 if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) {
1185 std::scoped_lock<std::mutex> lock(m_params_ui_mutex);
1186 m_params = m_params_ui = it_params->second;
1187 }
1188 }
1189#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1190 else {
1191 std::cout << std::endl << "Unable to connect to device:" << std::endl;
1192 std::cout << "Manufacturer/product: " << m_device_str << std::endl;
1193 std::cout << "Manufacturer id.....: " << vendor_id << " (" << std::hex << vendor_id << std::dec << ")" << std::endl;
1194 std::cout << "Product id..........: " << product_id << " (" << std::hex << product_id << std::dec << ")" << std::endl;
1195 std::cout << "Path................: '" << path << "'" << std::endl;
1196 }
1197#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1198
1199 return (m_device != nullptr);
1200}
#define L(s)
Definition ExtrusionEntity.cpp:25
static const std::vector< int > _3DCONNEXION_VENDORS
Definition Mouse3DController.cpp:50
static const std::vector< int > _3DCONNEXION_DEVICES
Definition Mouse3DController.cpp:57
std::condition_variable m_stop_condition
Definition Mouse3DController.hpp:175
std::string m_device_str
Definition Mouse3DController.hpp:161
std::mutex m_stop_condition_mutex
Definition Mouse3DController.hpp:174
bool m_stop
Definition Mouse3DController.hpp:168
std::map< std::string, Params > m_params_by_device
Definition Mouse3DController.hpp:157
std::string into_u8(const wxString &str)
Definition GUI.cpp:549
void trace(unsigned int level, const char *message)
Definition utils.cpp:247

References _3DCONNEXION_DEVICES, _3DCONNEXION_VENDORS, Slic3r::GUI::into_u8(), L, m_device, m_device_str, m_params, m_params_by_device, m_params_ui, m_params_ui_mutex, m_stop, m_stop_condition, m_stop_condition_mutex, and Slic3r::trace().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ connected()

bool Slic3r::GUI::Mouse3DController::connected ( ) const
inline
197{ return m_connected; }

References m_connected.

Referenced by can_show_settings_dialog(), and show_settings_dialog().

Here is the caller graph for this function:

◆ disconnect_device()

void Slic3r::GUI::Mouse3DController::disconnect_device ( )
private
1203{
1204 if (m_device) {
1205 hid_close(m_device);
1206 m_device = nullptr;
1207 BOOST_LOG_TRIVIAL(info) << "Disconnected device: " << m_device_str;
1208 // Copy the current parameters for m_device_str into the parameter database.
1209 {
1210 std::scoped_lock<std::mutex> lock(m_params_ui_mutex);
1212 }
1213 m_device_str.clear();
1214 m_connected = false;
1215#ifdef _WIN32
1216 // Enumerate once immediately after disconnect.
1217 m_wakeup = true;
1218#endif // _WIN32
1219 wxGetApp().plater()->CallAfter([]() {
1220 Plater *plater = wxGetApp().plater();
1221 if (plater != nullptr) {
1224 }
1225 });
1226 }
1227}
void set_current_canvas_as_dirty()
Definition Plater.cpp:22140
const Camera & get_camera() const
Definition Plater.cpp:22567
static Plater * plater()
Definition GUI_Factories.cpp:400
@ Plater
Definition Shortcuts.hpp:21
void recover_from_free_camera()
Definition Camera.hpp:177

References m_connected, m_device, m_device_str, m_params_by_device, m_params_ui, m_params_ui_mutex, and Slic3r::GUI::plater().

Referenced by collect_input(), and run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_input()

bool Slic3r::GUI::Mouse3DController::handle_input ( const DataPacketRaw & packet,
const int packet_length,
const Params & params,
State & state_in_out )
staticprivate
1304{
1305 if (! wxGetApp().IsActive())
1306 return false;
1307
1308 int res = packet_length;
1309 bool updated = false;
1310
1311 if (res == 7 || res == 13 ||
1312 // On Mac button packets can be 3 bytes long
1313 ((res == 3) && (packet[0] == 3)))
1314 updated = handle_packet(packet, res, params, state_in_out);
1315#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1316 else if (res > 0)
1317 std::cout << "Got unknown data packet of length: " << res << ", code:" << (int)packet[0] << std::endl;
1318#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1319
1320 if (updated) {
1321 wxGetApp().plater()->set_current_canvas_as_dirty();
1322 // ask for an idle event to update 3D scene
1323 wxWakeUpIdle();
1324 }
1325 return updated;
1326}
static bool handle_packet(const DataPacketRaw &packet, const int packet_length, const Params &params, State &state_in_out)
Definition Mouse3DController.cpp:1329

References handle_packet().

Referenced by collect_input().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_packet()

bool Slic3r::GUI::Mouse3DController::handle_packet ( const DataPacketRaw & packet,
const int packet_length,
const Params & params,
State & state_in_out )
staticprivate
1330{
1331 switch (packet[0])
1332 {
1333 case 1: // Translation + Rotation
1334 {
1335 bool updated = handle_packet_translation(packet, params, state_in_out);
1336 if (packet_length == 13)
1337 updated |= handle_packet_rotation(packet, 7, params, state_in_out);
1338
1339 if (updated)
1340 return true;
1341
1342 break;
1343 }
1344 case 2: // Rotation
1345 {
1346 if (handle_packet_rotation(packet, 1, params, state_in_out))
1347 return true;
1348
1349 break;
1350 }
1351 case 3: // Button
1352 {
1353 if (params.buttons_enabled && handle_packet_button(packet, packet.size() - 1, params, state_in_out))
1354 return true;
1355
1356 break;
1357 }
1358 case 23: // Battery charge
1359 {
1360#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1361 std::cout << "3DConnexion - battery level: " << (int)packet[1] << " percent" << std::endl;
1362#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1363 break;
1364 }
1365 default:
1366 {
1367#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1368 std::cout << "3DConnexion - Got unknown data packet of code: " << (int)packet[0] << std::endl;
1369#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
1370 break;
1371 }
1372 }
1373
1374 return false;
1375}
static bool handle_packet_rotation(const DataPacketRaw &packet, unsigned int first_byte, const Params &params, State &state_in_out)
Definition Mouse3DController.cpp:1405
static bool handle_packet_translation(const DataPacketRaw &packet, const Params &params, State &state_in_out)
Definition Mouse3DController.cpp:1388
static bool handle_packet_button(const DataPacketRaw &packet, unsigned int packet_size, const Params &params, State &state_in_out)
Definition Mouse3DController.cpp:1422

References Slic3r::GUI::Mouse3DController::Params::buttons_enabled, handle_packet_button(), handle_packet_rotation(), and handle_packet_translation().

Referenced by handle_input().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_packet_button()

bool Slic3r::GUI::Mouse3DController::handle_packet_button ( const DataPacketRaw & packet,
unsigned int packet_size,
const Params & params,
State & state_in_out )
staticprivate
1423{
1424 unsigned int data = 0;
1425 for (unsigned int i = 1; i < packet_size; ++i)
1426 {
1427 data |= packet[i] << 8 * (i - 1);
1428 }
1429
1430 const std::bitset<32> data_bits{ data };
1431 for (size_t i = 0; i < data_bits.size(); ++i)
1432 {
1433 if (data_bits.test(i))
1434 {
1435 state_in_out.append_button((unsigned int)i, params.input_queue_max_size);
1436 return true;
1437 }
1438 }
1439
1440 return false;
1441}

References Slic3r::GUI::Mouse3DController::State::append_button(), and Slic3r::GUI::Mouse3DController::Params::input_queue_max_size.

Referenced by handle_packet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_packet_rotation()

bool Slic3r::GUI::Mouse3DController::handle_packet_rotation ( const DataPacketRaw & packet,
unsigned int first_byte,
const Params & params,
State & state_in_out )
staticprivate
1406{
1407 double deadzone = (double)params.rotation.deadzone;
1408 Vec3f rotation((float)convert_input(packet[first_byte + 0], packet[first_byte + 1], deadzone),
1409 (float)convert_input(packet[first_byte + 2], packet[first_byte + 3], deadzone),
1410 (float)convert_input(packet[first_byte + 4], packet[first_byte + 5], deadzone));
1411
1412 if (!rotation.isApprox(Vec3f::Zero()))
1413 {
1414 state_in_out.append_rotation(rotation, params.input_queue_max_size);
1415 return true;
1416 }
1417
1418 return false;
1419}
static double convert_input(int coord_byte_low, int coord_byte_high, double deadzone)
Definition Mouse3DController.cpp:1378

References Slic3r::GUI::Mouse3DController::State::append_rotation(), Slic3r::GUI::convert_input(), Slic3r::GUI::Mouse3DController::Params::CustomParameters< Number >::deadzone, Slic3r::GUI::Mouse3DController::Params::input_queue_max_size, and Slic3r::GUI::Mouse3DController::Params::rotation.

Referenced by handle_packet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_packet_translation()

bool Slic3r::GUI::Mouse3DController::handle_packet_translation ( const DataPacketRaw & packet,
const Params & params,
State & state_in_out )
staticprivate
1389{
1390 double deadzone = params.translation.deadzone;
1391 Vec3d translation(-convert_input(packet[1], packet[2], deadzone),
1392 convert_input(packet[3], packet[4], deadzone),
1393 convert_input(packet[5], packet[6], deadzone));
1394
1395 if (!translation.isApprox(Vec3d::Zero()))
1396 {
1397 state_in_out.append_translation(translation, params.input_queue_max_size);
1398 return true;
1399 }
1400
1401 return false;
1402}

References Slic3r::GUI::Mouse3DController::State::append_translation(), Slic3r::GUI::convert_input(), Slic3r::GUI::Mouse3DController::Params::CustomParameters< Number >::deadzone, Slic3r::GUI::Mouse3DController::Params::input_queue_max_size, and Slic3r::GUI::Mouse3DController::Params::translation.

Referenced by handle_packet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

void Slic3r::GUI::Mouse3DController::init ( )
815{
816#ifdef _WIN32
817 if (wxGetApp().app_config->get("skip_3dmouse_detect") == "true")
818 BOOST_LOG_TRIVIAL(info) << "do not detect 3d Mouse";
819 else
820 m_device_str = detect_attached_device();
821 if (!m_device_str.empty()) {
822 m_connected = true;
823 if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end())
824 m_params = m_params_ui = it_params->second;
825 }
826#endif // _WIN32
827
828 assert(! m_thread.joinable());
829 if (! m_thread.joinable()) {
830 m_stop = false;
831#ifndef _WIN32
832 // Don't start the background thread on Windows, as the HID messages are sent as Windows messages.
833 m_thread = std::thread(&Mouse3DController::run, this);
834#endif // _WIN32
835 }
836}
std::thread m_thread
Definition Mouse3DController.hpp:165
void run()
Definition Mouse3DController.cpp:861

References m_connected, m_device_str, m_params, m_params_by_device, m_params_ui, m_stop, m_thread, and run().

Here is the call graph for this function:

◆ is_settings_dialog_shown()

bool Slic3r::GUI::Mouse3DController::is_settings_dialog_shown ( ) const
inline
226{ return m_show_settings_dialog; }

References m_show_settings_dialog.

Referenced by Slic3r::GUI::GLCanvas3D::handle_shortcut(), and Slic3r::GUI::MainFrame::init_menubar_as_editor().

Here is the caller graph for this function:

◆ load_config()

void Slic3r::GUI::Mouse3DController::load_config ( const AppConfig & appconfig)
370{
371 // We do not synchronize m_params_by_device with the background thread explicitely
372 // as there should be a full memory barrier executed once the background thread is started.
373 m_params_by_device.clear();
374
375 for (const std::string &device_name : appconfig.get_mouse_device_names()) {
376 double translation_speed = 4.0;
377 float rotation_speed = 4.0;
378 double translation_deadzone = Params::DefaultTranslationDeadzone;
379 float rotation_deadzone = Params::DefaultRotationDeadzone;
380 double zoom_speed = 2.0;
381 bool swap_yz = false;
382 bool invert_x = false;
383 bool invert_y = false;
384 bool invert_z = false;
385 bool invert_yaw = false;
386 bool invert_pitch = false;
387 bool invert_roll = false;
388 appconfig.get_mouse_device_translation_speed(device_name, translation_speed);
389 appconfig.get_mouse_device_translation_deadzone(device_name, translation_deadzone);
390 appconfig.get_mouse_device_rotation_speed(device_name, rotation_speed);
391 appconfig.get_mouse_device_rotation_deadzone(device_name, rotation_deadzone);
392 appconfig.get_mouse_device_zoom_speed(device_name, zoom_speed);
393 appconfig.get_mouse_device_swap_yz(device_name, swap_yz);
394 appconfig.get_mouse_device_invert_x(device_name, invert_x);
395 appconfig.get_mouse_device_invert_y(device_name, invert_y);
396 appconfig.get_mouse_device_invert_z(device_name, invert_z);
397 appconfig.get_mouse_device_invert_yaw(device_name, invert_yaw);
398 appconfig.get_mouse_device_invert_pitch(device_name, invert_pitch);
399 appconfig.get_mouse_device_invert_roll(device_name, invert_roll);
400 // clamp to valid values
401 Params params;
403 params.translation.deadzone = std::clamp(translation_deadzone, 0.0, Params::MaxTranslationDeadzone);
404 params.rotation.scale = Params::DefaultRotationScale * std::clamp(rotation_speed, 0.1f, 10.0f);
405 params.rotation.deadzone = std::clamp(rotation_deadzone, 0.0f, Params::MaxRotationDeadzone);
406 params.zoom.scale = Params::DefaultZoomScale * std::clamp(zoom_speed, 0.1, 10.0);
407 params.swap_yz = swap_yz;
408 params.invert_x = invert_x;
409 params.invert_y = invert_y;
410 params.invert_z = invert_z;
411 params.invert_yaw = invert_yaw;
412 params.invert_pitch = invert_pitch;
413 params.invert_roll = invert_roll;
414 m_params_by_device[device_name] = std::move(params);
415 }
416}
Definition Mouse3DController.hpp:41
static constexpr double DefaultTranslationDeadzone
Definition Mouse3DController.hpp:46
static constexpr double DefaultTranslationScale
Definition Mouse3DController.hpp:44
static constexpr float MaxRotationDeadzone
Definition Mouse3DController.hpp:48
static constexpr float DefaultRotationDeadzone
Definition Mouse3DController.hpp:49
static constexpr float DefaultRotationScale
Definition Mouse3DController.hpp:47
Number scale
Definition Mouse3DController.hpp:55
static constexpr double MaxTranslationScale
Definition Mouse3DController.hpp:43
static constexpr double MaxTranslationDeadzone
Definition Mouse3DController.hpp:45
CustomParameters< double > translation
Definition Mouse3DController.hpp:59
static constexpr double DefaultZoomScale
Definition Mouse3DController.hpp:50
static constexpr double MinTranslationScale
Definition Mouse3DController.hpp:42

References Slic3r::GUI::Mouse3DController::Params::CustomParameters< Number >::deadzone, Slic3r::GUI::Mouse3DController::Params::DefaultRotationDeadzone, Slic3r::GUI::Mouse3DController::Params::DefaultRotationScale, Slic3r::GUI::Mouse3DController::Params::DefaultTranslationDeadzone, Slic3r::GUI::Mouse3DController::Params::DefaultTranslationScale, Slic3r::GUI::Mouse3DController::Params::DefaultZoomScale, Slic3r::AppConfig::get_mouse_device_invert_pitch(), Slic3r::AppConfig::get_mouse_device_invert_roll(), Slic3r::AppConfig::get_mouse_device_invert_x(), Slic3r::AppConfig::get_mouse_device_invert_y(), Slic3r::AppConfig::get_mouse_device_invert_yaw(), Slic3r::AppConfig::get_mouse_device_invert_z(), Slic3r::AppConfig::get_mouse_device_names(), Slic3r::AppConfig::get_mouse_device_rotation_deadzone(), Slic3r::AppConfig::get_mouse_device_rotation_speed(), Slic3r::AppConfig::get_mouse_device_swap_yz(), Slic3r::AppConfig::get_mouse_device_translation_deadzone(), Slic3r::AppConfig::get_mouse_device_translation_speed(), Slic3r::AppConfig::get_mouse_device_zoom_speed(), Slic3r::GUI::Mouse3DController::Params::invert_pitch, Slic3r::GUI::Mouse3DController::Params::invert_roll, Slic3r::GUI::Mouse3DController::Params::invert_x, Slic3r::GUI::Mouse3DController::Params::invert_y, Slic3r::GUI::Mouse3DController::Params::invert_yaw, Slic3r::GUI::Mouse3DController::Params::invert_z, m_params_by_device, Slic3r::GUI::Mouse3DController::Params::MaxRotationDeadzone, Slic3r::GUI::Mouse3DController::Params::MaxTranslationDeadzone, Slic3r::GUI::Mouse3DController::Params::MaxTranslationScale, Slic3r::GUI::Mouse3DController::Params::MinTranslationScale, Slic3r::GUI::Mouse3DController::Params::rotation, Slic3r::GUI::Mouse3DController::Params::CustomParameters< Number >::scale, Slic3r::GUI::Mouse3DController::Params::swap_yz, Slic3r::GUI::Mouse3DController::Params::translation, and Slic3r::GUI::Mouse3DController::Params::zoom.

Here is the call graph for this function:

◆ render_settings_dialog()

void Slic3r::GUI::Mouse3DController::render_settings_dialog ( GLCanvas3D & canvas) const
466{
468 return;
469
470 // when the user clicks on [X] or [Close] button we need to trigger
471 // an extra frame to let the dialog disappear
475 canvas.request_extra_frame();
476 return;
477 }
478
479 Params params_copy;
480 bool params_changed = false;
481 {
482 std::scoped_lock<std::mutex> lock(m_params_ui_mutex);
483 params_copy = m_params_ui;
484 }
485
486 Size cnv_size = canvas.get_canvas_size();
487
488 ImGuiWrapper& imgui = *wxGetApp().imgui();
489 imgui.set_next_window_pos(0.5f * (float)cnv_size.get_width(), 0.5f * (float)cnv_size.get_height(), ImGuiCond_Always, 0.5f, 0.5f);
490
491 float space_size = imgui.get_style_scaling() * 8;
492
493 float speed_size = imgui.calc_text_size(_L("Speed:")).x + imgui.scaled(1.5f);
494 float dead_size = imgui.calc_text_size(_L("Deadzone:")).x + imgui.scaled(1.5f);
495 float option_size = imgui.calc_text_size(_L("Options:")).x + imgui.scaled(1.5f);
496 float max_left_size = std::max(speed_size,std::max(dead_size,option_size)) + space_size;
497
498 float trans_size = imgui.calc_text_size(_L("Translate")).x + space_size;
499 float zoom_size = imgui.calc_text_size(_L("Zoom")).x + space_size;
500 float rota_size = imgui.calc_text_size(_L("Rotation")).x + space_size;
501 float trasn_zoom_size = imgui.calc_text_size(_L("Translation/Zoom")).x + space_size;
502 float max_slider_txt_size = std::max(std::max(trans_size,zoom_size),std::max(rota_size,trasn_zoom_size));
503
504 ImGuiWrapper::push_toolbar_style(wxGetApp().plater()->canvas3D()->get_scale());
505 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 20.0f));
506 static ImVec2 last_win_size(0.0f, 0.0f);
507 bool shown = true;
508 if (imgui.begin(_L("3Dconnexion settings"), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar)) {
509 if (shown) {
510 ImVec2 win_size = ImGui::GetWindowSize();
511 if (last_win_size.x != win_size.x || last_win_size.y != win_size.y) {
512 // when the user clicks on [X] button, the next time the dialog is shown
513 // has a dummy size, so we trigger an extra frame to let it have the correct size
514 last_win_size = win_size;
515 canvas.request_extra_frame();
516 }
517
518 const ImVec4& color = ImVec4(0.56f, 0.56f, 0.56f, 1.00f);
519 /*imgui.text(_L("Device:"));
520 ImGui::SameLine();
521 imgui.text(m_device_str);*/
522 ImGui::AlignTextToFramePadding();
523 imgui.text_colored(color,_L("Speed:"));
524 ImGui::SameLine(max_left_size + max_slider_txt_size - trans_size);
525 imgui.text(_L("Translate"));
526 ImGui::SameLine(max_left_size + max_slider_txt_size);
527
528 ImGui::PushItemWidth(imgui.scaled(6.0f));
529 float translation_scale = float(params_copy.translation.scale) / float(Params::DefaultTranslationScale);
530 bool b_translation = imgui.bbl_slider_float_style("##Translate", &translation_scale, float(Params::MinTranslationScale), float(Params::MaxTranslationScale), "%.1f");
531 ImGui::SameLine();
532 ImGui::PushItemWidth(imgui.scaled(3.0f));
533 bool b_translation_dragfloat = ImGui::BBLDragFloat("##Translate_input", &translation_scale, float(Params::MinTranslationScale), float(Params::MaxTranslationScale),0.0, "%.1f");
534 if (b_translation || b_translation_dragfloat) {
535 params_copy.translation.scale = Params::DefaultTranslationScale * double(translation_scale);
536 params_changed = true;
537 }
538 ImGui::SameLine();
539 ImGui::Dummy({space_size, 0.0});
540
541 ImGui::Dummy({0.0, 0.0});
542 ImGui::SameLine(max_left_size + max_slider_txt_size - rota_size);
543 ImGui::AlignTextToFramePadding();
544 imgui.text(_L("Rotation"));
545 ImGui::SameLine(max_left_size + max_slider_txt_size);
546 ImGui::PushItemWidth(imgui.scaled(6.0f));
547 float rotation_scale = params_copy.rotation.scale / Params::DefaultRotationScale;
548 bool b_rotation1 = imgui.bbl_slider_float_style("##Rotation1", &rotation_scale, 0.1f, 10.0f, "%.1f");
549 ImGui::SameLine();
550 ImGui::PushItemWidth(imgui.scaled(3.0f));
551 bool b_rotation1_dragfloat = ImGui::BBLDragFloat("##Rotation1_input", &rotation_scale, 0.1f, 10.0f, 0.0, "%.1f");
552 if (b_rotation1 || b_rotation1_dragfloat) {
553 params_copy.rotation.scale = Params::DefaultRotationScale * rotation_scale;
554 params_changed = true;
555 }
556 ImGui::SameLine();
557 ImGui::Dummy({space_size, 0.0});
558
559 ImGui::Dummy({0.0, 0.0});
560 ImGui::SameLine(max_left_size + max_slider_txt_size - zoom_size);
561 ImGui::AlignTextToFramePadding();
562 imgui.text(_L("Zoom"));
563 ImGui::SameLine(max_left_size + max_slider_txt_size);
564 ImGui::PushItemWidth(imgui.scaled(6.0f));
565 float zoom_scale = params_copy.zoom.scale / Params::DefaultZoomScale;
566 bool b_zoom = imgui.bbl_slider_float_style("##Zoom", &zoom_scale, 0.1f, 10.0f, "%.1f");
567 ImGui::SameLine();
568 ImGui::PushItemWidth(imgui.scaled(3.0f));
569 bool b_zoom_dragfloat = ImGui::BBLDragFloat("##Zoom_input", &zoom_scale, 0.1f, 10.0f, 0.0, "%.1f");
570 if (b_zoom || b_zoom_dragfloat) {
571 params_copy.zoom.scale = Params::DefaultZoomScale * zoom_scale;
572 params_changed = true;
573 }
574
575 ImGui::Separator();
576 ImGui::AlignTextToFramePadding();
577 imgui.text_colored(color,_L("Deadzone:"));
578 ImGui::SameLine(max_left_size + max_slider_txt_size - trasn_zoom_size);
579 imgui.text(_L("Translation/Zoom"));
580 ImGui::SameLine(max_left_size + max_slider_txt_size);
581
582 ImGui::PushItemWidth(imgui.scaled(6.0f));
583 float translation_deadzone = (float) params_copy.translation.deadzone;
584 bool b_tran_zoom = imgui.bbl_slider_float_style("##Translation/Zoom", &translation_deadzone, 0.0f, (float) Params::MaxTranslationDeadzone, "%.2f");
585 ImGui::SameLine();
586 ImGui::PushItemWidth(imgui.scaled(3.0f));
587 bool b_tran_zoom_dragfloat = ImGui::BBLDragFloat("##Translation/Zoom_input", &translation_deadzone, 0.0f, (float) Params::MaxTranslationDeadzone, 0.0, "%.1f");
588 if (b_tran_zoom || b_tran_zoom_dragfloat) {
589 params_copy.translation.deadzone = (double) translation_deadzone;
590 params_changed = true;
591 }
592 ImGui::SameLine();
593 ImGui::Dummy({space_size, 0.0});
594
595 ImGui::Dummy({0.0, 0.0});
596 ImGui::SameLine(max_left_size + max_slider_txt_size - rota_size);
597 ImGui::AlignTextToFramePadding();
598 imgui.text(_L("Rotation"));
599 ImGui::SameLine(max_left_size + max_slider_txt_size);
600 ImGui::PushItemWidth(imgui.scaled(6.0f));
601 float rotation_deadzone = params_copy.rotation.deadzone;
602 bool b_rotation2 = imgui.bbl_slider_float_style("##Rotation2", &rotation_deadzone, 0.0f, Params::MaxRotationDeadzone, "%.2f");
603 ImGui::SameLine();
604 ImGui::PushItemWidth(imgui.scaled(3.0f));
605 bool b_rotation2_dragfloat = ImGui::BBLDragFloat("##Rotation2_input", &rotation_deadzone, 0.0f, Params::MaxRotationDeadzone, 0.0, "%.1f");
606 if (b_rotation2 || b_rotation2_dragfloat) {
607 params_copy.rotation.deadzone = rotation_deadzone;
608 params_changed = true;
609 }
610 ImGui::SameLine();
611 ImGui::Dummy({space_size, 0.0});
612 ImGui::PopItemWidth();
613
614 ImGui::Separator();
615 ImGui::AlignTextToFramePadding();
616 imgui.text_colored(color,_L("Options:"));
617 ImGui::SameLine(max_left_size + max_slider_txt_size - imgui.get_slider_icon_size().x + + space_size);
618
619 bool swap_yz = params_copy.swap_yz;
620 if (imgui.bbl_checkbox(_L("Swap Y/Z axes"), swap_yz)) {
621 params_copy.swap_yz = swap_yz;
622 params_changed = true;
623 }
624 ImGui::Dummy({0.0, 0.0});
625 ImGui::SameLine(max_left_size + max_slider_txt_size - imgui.get_slider_icon_size().x + + space_size);
626 bool invert_x = params_copy.invert_x;
627 if (imgui.bbl_checkbox(_L("Invert X axis"), invert_x)) {
628 params_copy.invert_x = invert_x;
629 params_changed = true;
630 }
631 ImGui::Dummy({0.0, 0.0});
632 ImGui::SameLine(max_left_size + max_slider_txt_size - imgui.get_slider_icon_size().x + + space_size);
633 bool invert_y = params_copy.invert_y;
634 if (imgui.bbl_checkbox(_L("Invert Y axis"), invert_y)) {
635 params_copy.invert_y = invert_y;
636 params_changed = true;
637 }
638 ImGui::Dummy({0.0, 0.0});
639 ImGui::SameLine(max_left_size + max_slider_txt_size - imgui.get_slider_icon_size().x + + space_size);
640 bool invert_z = params_copy.invert_z;
641 if (imgui.bbl_checkbox(_L("Invert Z axis"), invert_z)) {
642 params_copy.invert_z = invert_z;
643 params_changed = true;
644 }
645 ImGui::Dummy({0.0, 0.0});
646 ImGui::SameLine(max_left_size + max_slider_txt_size - imgui.get_slider_icon_size().x + + space_size);
647 bool invert_yaw = params_copy.invert_yaw;
648 if (imgui.bbl_checkbox(_L("Invert Yaw axis"), invert_yaw)) {
649 params_copy.invert_yaw = invert_yaw;
650 params_changed = true;
651 }
652 ImGui::Dummy({0.0, 0.0});
653 ImGui::SameLine(max_left_size + max_slider_txt_size - imgui.get_slider_icon_size().x + + space_size);
654 bool invert_pitch = params_copy.invert_pitch;
655 if (imgui.bbl_checkbox(_L("Invert Pitch axis"), invert_pitch)) {
656 params_copy.invert_pitch = invert_pitch;
657 params_changed = true;
658 }
659 ImGui::Dummy({0.0, 0.0});
660 ImGui::SameLine(max_left_size + max_slider_txt_size - imgui.get_slider_icon_size().x + + space_size);
661 bool invert_roll = params_copy.invert_roll;
662 if (imgui.bbl_checkbox(_L("Invert Roll axis"), invert_roll)) {
663 params_copy.invert_roll = invert_roll;
664 params_changed = true;
665 }
666 ImGui::Dummy({0.0, 0.0});
667 ImGui::SameLine(max_left_size + max_slider_txt_size - imgui.get_slider_icon_size().x + + space_size);
668
669#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
670 ImGui::Separator();
671 ImGui::Separator();
672 imgui.text_colored(color, "DEBUG:");
673 imgui.text_colored(color, "Vectors:");
674 Vec3f translation = m_state.get_first_vector_of_type(State::QueueItem::TranslationType).cast<float>();
675 Vec3f rotation = m_state.get_first_vector_of_type(State::QueueItem::RotationType).cast<float>();
676 ImGui::InputFloat3("Translation##2", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
677 ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
678
679 imgui.text_colored(color, "Queue size:");
680
681 int input_queue_size_current[2] = { int(m_state.input_queue_size_current()), int(m_state.input_queue_max_size_achieved) };
682 ImGui::InputInt2("Current", input_queue_size_current, ImGuiInputTextFlags_ReadOnly);
683
684 int input_queue_size_param = int(params_copy.input_queue_max_size);
685 if (ImGui::InputInt("Max size", &input_queue_size_param, 1, 1, ImGuiInputTextFlags_ReadOnly)) {
686 if (input_queue_size_param > 0) {
687 params_copy.input_queue_max_size = input_queue_size_param;
688 params_changed = true;
689 }
690 }
691
692 ImGui::Separator();
693 imgui.text_colored(color, "Camera:");
694 Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
695 ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
696#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
697
698 ImGui::Separator();
699 float window_width = ImGui::GetWindowWidth();
700 ImGui::Dummy({0.0, 0.0});
701 ImGui::SameLine((window_width - imgui.calc_text_size(_L("Close")).x)/2);
702 if (imgui.button(_L("Close"))) {
703 // the user clicked on the [Close] button
705 canvas.set_as_dirty();
706 }
707 }
708 else {
709 // the user clicked on the [X] button
711 canvas.set_as_dirty();
712 }
713 }
714
715 imgui.end();
716 ImGui::PopStyleVar(1);
718 if (params_changed) {
719 // Synchronize front end parameters to back end.
720 std::scoped_lock<std::mutex> lock(m_params_ui_mutex);
721 auto pthis = const_cast<Mouse3DController*>(this);
722#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
723 if (params_copy.input_queue_max_size != params_copy.input_queue_max_size)
724 // Reset the statistics counter.
725 m_state.input_queue_max_size_achieved = 0;
726#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
727 pthis->m_params_ui = params_copy;
728 pthis->m_params_ui_changed = true;
729 }
730}
#define _L(s)
Definition OBJ.cpp:34
static void push_toolbar_style(const float scale)
Definition ImGuiWrapper.cpp:2705
static void pop_toolbar_style()
Definition ImGuiWrapper.cpp:2757
static constexpr unsigned int TranslationType
Definition Mouse3DController.hpp:95
static constexpr unsigned int RotationType
Definition Mouse3DController.hpp:96

References _L, Slic3r::GUI::ImGuiWrapper::bbl_checkbox(), Slic3r::GUI::ImGuiWrapper::bbl_slider_float_style(), Slic3r::GUI::ImGuiWrapper::begin(), Slic3r::GUI::ImGuiWrapper::button(), Slic3r::GUI::ImGuiWrapper::calc_text_size(), Slic3r::GUI::Mouse3DController::Params::CustomParameters< Number >::deadzone, Slic3r::GUI::Mouse3DController::Params::DefaultRotationScale, Slic3r::GUI::Mouse3DController::Params::DefaultTranslationScale, Slic3r::GUI::Mouse3DController::Params::DefaultZoomScale, Slic3r::GUI::ImGuiWrapper::end(), Slic3r::GUI::GLCanvas3D::get_canvas_size(), Slic3r::GUI::Size::get_height(), Slic3r::GUI::ImGuiWrapper::get_style_scaling(), Slic3r::GUI::Size::get_width(), Slic3r::GUI::Mouse3DController::Params::input_queue_max_size, Slic3r::GUI::Mouse3DController::Params::invert_pitch, Slic3r::GUI::Mouse3DController::Params::invert_roll, Slic3r::GUI::Mouse3DController::Params::invert_x, Slic3r::GUI::Mouse3DController::Params::invert_y, Slic3r::GUI::Mouse3DController::Params::invert_yaw, Slic3r::GUI::Mouse3DController::Params::invert_z, m_connected, m_params_ui, m_params_ui_mutex, m_settings_dialog_closed_by_user, m_show_settings_dialog, m_state, Slic3r::GUI::Mouse3DController::Params::MaxRotationDeadzone, Slic3r::GUI::Mouse3DController::Params::MaxTranslationDeadzone, Slic3r::GUI::Mouse3DController::Params::MaxTranslationScale, Slic3r::GUI::Mouse3DController::Params::MinTranslationScale, Slic3r::GUI::plater(), Slic3r::GUI::ImGuiWrapper::pop_toolbar_style(), Slic3r::GUI::ImGuiWrapper::push_toolbar_style(), Slic3r::GUI::GLCanvas3D::request_extra_frame(), Slic3r::GUI::Mouse3DController::Params::rotation, Slic3r::GUI::Mouse3DController::State::QueueItem::RotationType, Slic3r::GUI::Mouse3DController::Params::CustomParameters< Number >::scale, Slic3r::GUI::ImGuiWrapper::scaled(), Slic3r::GUI::GLCanvas3D::set_as_dirty(), Slic3r::GUI::ImGuiWrapper::set_next_window_pos(), Slic3r::GUI::Mouse3DController::Params::swap_yz, Slic3r::GUI::ImGuiWrapper::text(), Slic3r::GUI::ImGuiWrapper::text_colored(), Slic3r::GUI::Mouse3DController::Params::translation, Slic3r::GUI::Mouse3DController::State::QueueItem::TranslationType, and Slic3r::GUI::Mouse3DController::Params::zoom.

Here is the call graph for this function:

◆ run()

void Slic3r::GUI::Mouse3DController::run ( )
private
862{
863#ifdef HAVE_SPNAV
864 if (spnav_open() == -1) {
865 // Give up.
866 BOOST_LOG_TRIVIAL(error) << "Unable to open connection to spacenavd";
867 return;
868 }
869 m_connected = true;
870 m_device_str = "spacenavd";
871 if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) {
872 std::scoped_lock<std::mutex> lock(m_params_ui_mutex);
873 m_params = m_params_ui = it_params->second;
874 } else {
876 }
877
878 for (;;) {
879 {
880 std::scoped_lock lock(m_params_ui_mutex);
881 if (m_stop)
882 break;
885 m_params_ui_changed = false;
886 }
887 }
888 this->collect_input();
889 }
890
891 m_connected = false;
892 // Finalize the spnav library
893 spnav_close();
894#else
895 // Initialize the hidapi library
896 int res = hid_init();
897 if (res != 0) {
898 // Give up.
899#if defined(__unix__) || defined(__unix) || defined(unix)
900 if (res == -1)
901 // Hopefully this error code comes from our bundled patched hidapi. In that case, -1 is returned by hid_wrapper_udev_init() and it mean
902 BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library: failed to load libudev.so.1 or libudev.so.0";
903 else if (res == -2)
904 // Hopefully this error code comes from our bundled patched hidapi. In that case, -2 is returned by hid_wrapper_udev_init() and it mean
905 BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library: failed to resolve some function from libudev.so.1 or libudev.so.0";
906 else
907#endif // unixes
908 BOOST_LOG_TRIVIAL(error) << "Unable to initialize hidapi library";
909 return;
910 }
911
912#ifdef _WIN32
913 // Enumerate once just after thread start.
914 m_wakeup = true;
915#endif // _WIN32
916
917 for (;;) {
918 {
919 std::scoped_lock<std::mutex> lock(m_params_ui_mutex);
920 if (m_stop)
921 break;
924 m_params_ui_changed = false;
925 }
926 }
927 if (m_device == nullptr)
928 // Polls the HID devices, blocks for maximum 2 seconds.
929 m_connected = this->connect_device();
930 else
931 // Waits for 3DConnexion mouse input for maximum 100ms, then repeats.
932 this->collect_input();
933 }
934
935 this->disconnect_device();
936
937 // Finalize the hidapi library
938 hid_exit();
939#endif
940}
bool connect_device()
Definition Mouse3DController.cpp:942
void collect_input()
Definition Mouse3DController.cpp:1237

References collect_input(), connect_device(), disconnect_device(), m_connected, m_device, m_device_str, m_params, m_params_by_device, m_params_ui, m_params_ui_changed, m_params_ui_mutex, and m_stop.

Referenced by init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ save_config()

void Slic3r::GUI::Mouse3DController::save_config ( AppConfig & appconfig) const
420{
421 // We do not synchronize m_params_by_device with the background thread explicitely
422 // as there should be a full memory barrier executed once the background thread is stopped.
423
424 for (const auto &key_value_pair : m_params_by_device) {
425 const std::string &device_name = key_value_pair.first;
426 const Params &params = key_value_pair.second;
427 // Store current device parameters into the config
428 appconfig.set_mouse_device(device_name, params.translation.scale / Params::DefaultTranslationScale, params.translation.deadzone,
429 params.rotation.scale / Params::DefaultRotationScale, params.rotation.deadzone, params.zoom.scale / Params::DefaultZoomScale,
430 params.swap_yz, params.invert_x, params.invert_y, params.invert_z, params.invert_yaw, params.invert_pitch, params.invert_roll);
431 }
432}

References Slic3r::GUI::Mouse3DController::Params::CustomParameters< Number >::deadzone, Slic3r::GUI::Mouse3DController::Params::DefaultRotationScale, Slic3r::GUI::Mouse3DController::Params::DefaultTranslationScale, Slic3r::GUI::Mouse3DController::Params::DefaultZoomScale, Slic3r::GUI::Mouse3DController::Params::invert_pitch, Slic3r::GUI::Mouse3DController::Params::invert_roll, Slic3r::GUI::Mouse3DController::Params::invert_x, Slic3r::GUI::Mouse3DController::Params::invert_y, Slic3r::GUI::Mouse3DController::Params::invert_yaw, Slic3r::GUI::Mouse3DController::Params::invert_z, m_params_by_device, Slic3r::GUI::Mouse3DController::Params::rotation, Slic3r::GUI::Mouse3DController::Params::CustomParameters< Number >::scale, Slic3r::AppConfig::set_mouse_device(), Slic3r::GUI::Mouse3DController::Params::swap_yz, Slic3r::GUI::Mouse3DController::Params::translation, and Slic3r::GUI::Mouse3DController::Params::zoom.

Here is the call graph for this function:

◆ show_settings_dialog()

void Slic3r::GUI::Mouse3DController::show_settings_dialog ( bool show)
inline
227{ m_show_settings_dialog = show && this->connected(); }

References connected(), and m_show_settings_dialog.

Referenced by Slic3r::GUI::GLCanvas3D::handle_shortcut(), and Slic3r::GUI::MainFrame::init_menubar_as_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ shutdown()

void Slic3r::GUI::Mouse3DController::shutdown ( )
840{
841 if (m_thread.joinable()) {
842 // Stop the worker thread, if running.
843 {
844 // Notify the worker thread to cancel wait on detection polling.
845 std::lock_guard<std::mutex> lock(m_stop_condition_mutex);
846 m_stop = true;
847 }
848 m_stop_condition.notify_all();
849 // Wait for the worker thread to stop.
850 m_thread.join();
851 m_stop = false;
852 }
853
854#ifdef _WIN32
855 if (!m_device_str.empty())
857#endif // _WIN32
858}

References m_device_str, m_params_by_device, m_params_ui, m_stop, m_stop_condition, m_stop_condition_mutex, and m_thread.

Member Data Documentation

◆ m_connected

std::atomic<bool> Slic3r::GUI::Mouse3DController::m_connected { false }
private

◆ m_device

hid_device* Slic3r::GUI::Mouse3DController::m_device { nullptr }
private
166{ nullptr };

Referenced by collect_input(), connect_device(), disconnect_device(), and run().

◆ m_device_str

std::string Slic3r::GUI::Mouse3DController::m_device_str
private

◆ m_params

Params Slic3r::GUI::Mouse3DController::m_params
private

◆ m_params_by_device

std::map<std::string, Params> Slic3r::GUI::Mouse3DController::m_params_by_device
private

◆ m_params_ui

Params Slic3r::GUI::Mouse3DController::m_params_ui
private

◆ m_params_ui_changed

bool Slic3r::GUI::Mouse3DController::m_params_ui_changed { false }
private
150{ false };

Referenced by apply(), and run().

◆ m_params_ui_mutex

std::mutex Slic3r::GUI::Mouse3DController::m_params_ui_mutex
mutableprivate

◆ m_settings_dialog_closed_by_user

bool Slic3r::GUI::Mouse3DController::m_settings_dialog_closed_by_user { false }
mutableprivate
181{ false };

Referenced by apply(), and render_settings_dialog().

◆ m_show_settings_dialog

bool Slic3r::GUI::Mouse3DController::m_show_settings_dialog { false }
mutableprivate

◆ m_state

State Slic3r::GUI::Mouse3DController::m_state
mutableprivate

◆ m_stop

bool Slic3r::GUI::Mouse3DController::m_stop { false }
private
168{ false };

Referenced by connect_device(), init(), run(), and shutdown().

◆ m_stop_condition

std::condition_variable Slic3r::GUI::Mouse3DController::m_stop_condition
private

Referenced by connect_device(), and shutdown().

◆ m_stop_condition_mutex

std::mutex Slic3r::GUI::Mouse3DController::m_stop_condition_mutex
private

Referenced by connect_device(), and shutdown().

◆ m_thread

std::thread Slic3r::GUI::Mouse3DController::m_thread
private

Referenced by init(), and shutdown().


The documentation for this class was generated from the following files: